version 3.8
subdomainstaggeredlocalassembler.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
14#ifndef DUMUX_MULTIDOMAIN_STAGGERED_LOCAL_ASSEMBLER_HH
15#define DUMUX_MULTIDOMAIN_STAGGERED_LOCAL_ASSEMBLER_HH
16
17#include <dune/common/reservedvector.hh>
18#include <dune/common/indices.hh>
19#include <dune/common/hybridutilities.hh>
20#include <dune/grid/common/gridenums.hh> // for GhostEntity
21
30
31namespace Dumux {
32
44template<std::size_t id, class TypeTag, class Assembler, class Implementation, bool isImplicit = true>
45class SubDomainStaggeredLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler,Implementation, isImplicit>
46{
48
50 using SolutionVector = typename Assembler::SolutionVector;
51
53 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
54 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
55 using Scalar = typename GridVariables::Scalar;
56
57 using ElementFaceVariables = typename GetPropType<TypeTag, Properties::GridFaceVariables>::LocalView;
58 using CellCenterResidualValue = typename ParentType::LocalResidual::CellCenterResidualValue;
59 using FaceResidualValue = typename ParentType::LocalResidual::FaceResidualValue;
60
61 using GridGeometry = typename GridVariables::GridGeometry;
62 using FVElementGeometry = typename GridGeometry::LocalView;
63 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
64 using GridView = typename GridGeometry::GridView;
65 using Element = typename GridView::template Codim<0>::Entity;
66
67 using CouplingManager = typename Assembler::CouplingManager;
68
69 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
70
71public:
72 static constexpr auto domainId = typename Dune::index_constant<id>();
73 static constexpr auto cellCenterId = GridGeometry::cellCenterIdx();
74 static constexpr auto faceId = GridGeometry::faceIdx();
75
76 static constexpr auto numEqCellCenter = CellCenterResidualValue::dimension;
77 static constexpr auto faceOffset = numEqCellCenter;
78
79 using ParentType::ParentType;
80
82 const Element& element,
83 const SolutionVector& curSol,
84 CouplingManager& couplingManager)
86 element,
87 curSol,
88 localView(assembler.gridGeometry(domainId)),
89 localView(assembler.gridVariables(domainId).curGridVolVars()),
90 localView(assembler.gridVariables(domainId).prevGridVolVars()),
91 localView(assembler.gridVariables(domainId).gridFluxVarsCache()),
93 (element.partitionType() == Dune::GhostEntity))
94 , curElemFaceVars_(localView(assembler.gridVariables(domainId).curGridFaceVars()))
95 , prevElemFaceVars_(localView(assembler.gridVariables(domainId).prevGridFaceVars()))
96 , couplingManager_(couplingManager)
97 {}
98
103 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
104 void assembleJacobianAndResidual(JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
105 {
106 this->asImp_().bindLocalViews();
107 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
108
109 assembleJacobianAndResidualImpl_(domainId, jacRow, res, gridVariables);
110 }
111
115 template<class SubResidual>
116 void assembleResidual(SubResidual& res)
117 {
118 this->asImp_().bindLocalViews();
119 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
120
121 if constexpr (domainId == cellCenterId)
122 {
123 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
124 res[cellCenterGlobalI] = this->asImp_().assembleCellCenterResidualImpl();
125 }
126 else
127 {
128 for (auto&& scvf : scvfs(this->fvGeometry()))
129 res[scvf.dofIndex()] += this->asImp_().assembleFaceResidualImpl(scvf);
130 }
131 }
132
137 CellCenterResidualValue evalLocalResidualForCellCenter() const
138 {
139 if (!isImplicit)
140 if (this->assembler().isStationaryProblem())
141 DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
142
143 if (this->elementIsGhost())
144 {
145 return CellCenterResidualValue(0.0);
146 }
147
150 }
151
157 CellCenterResidualValue evalLocalResidualForCellCenter(const ElementVolumeVariables& elemVolVars,
158 const ElementFaceVariables& elemFaceVars) const
159 {
160 auto residual = evalLocalFluxAndSourceResidualForCellCenter(elemVolVars, elemFaceVars);
161
162 if (!this->assembler().isStationaryProblem())
164
165 // handle cells with a fixed Dirichlet value
166 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
167 const auto& scvI = this->fvGeometry().scv(cellCenterGlobalI);
168 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
169 {
170 static constexpr auto offset = numEq - numEqCellCenter;
171 if (this->problem().isDirichletCell(this->element(), this->fvGeometry(), scvI, pvIdx + offset))
172 residual[pvIdx] = this->curSol()[cellCenterId][cellCenterGlobalI][pvIdx] - this->problem().dirichlet(this->element(), scvI)[pvIdx + offset];
173 }
174
175 return residual;
176 }
177
183 CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter() const
184 {
187 }
188
196 CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter(const ElementVolumeVariables& elemVolVars, const ElementFaceVariables& elemFaceVars) const
197 {
198 return this->localResidual().evalFluxAndSourceForCellCenter(this->element(), this->fvGeometry(), elemVolVars, elemFaceVars, this->elemBcTypes(), this->elemFluxVarsCache());
199 }
200
206 CellCenterResidualValue evalLocalStorageResidualForCellCenter() const
207 {
208 return this->localResidual().evalStorageForCellCenter(this->element(), this->fvGeometry(), this->prevElemVolVars(), this->curElemVolVars());
209 }
210
216 FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace& scvf) const
217 {
218 if (!isImplicit)
219 if (this->assembler().isStationaryProblem())
220 DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
221
222 if (this->elementIsGhost())
223 {
224 return FaceResidualValue(0.0);
225 }
226
229 }
230
237 FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace& scvf,
238 const ElementVolumeVariables& elemVolVars,
239 const ElementFaceVariables& elemFaceVars) const
240 {
241 auto residual = evalLocalFluxAndSourceResidualForFace(scvf, elemVolVars, elemFaceVars);
242
243 if (!this->assembler().isStationaryProblem())
244 residual += evalLocalStorageResidualForFace(scvf);
245
246 this->localResidual().evalDirichletBoundariesForFace(residual, this->problem(), this->element(),
247 this->fvGeometry(), scvf, elemVolVars, elemFaceVars,
248 this->elemBcTypes(), this->elemFluxVarsCache());
249
250 return residual;
251 }
252
259 FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace& scvf) const
260 {
263 }
264
272 FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace& scvf,
273 const ElementVolumeVariables& elemVolVars,
274 const ElementFaceVariables& elemFaceVars) const
275 {
276 return this->localResidual().evalFluxAndSourceForFace(this->element(), this->fvGeometry(), elemVolVars, elemFaceVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
277 }
278
285 FaceResidualValue evalLocalStorageResidualForFace(const SubControlVolumeFace& scvf) const
286 {
287 return this->localResidual().evalStorageForFace(this->element(), this->fvGeometry(), this->prevElemVolVars(), this->curElemVolVars(), this->prevElemFaceVars(), this->curElemFaceVars(), scvf);
288 }
289
290 const Problem& problem() const
291 { return this->assembler().problem(domainId); }
292
294 ElementFaceVariables& curElemFaceVars()
295 { return curElemFaceVars_; }
296
298 ElementFaceVariables& prevElemFaceVars()
299 { return prevElemFaceVars_; }
300
302 const ElementFaceVariables& curElemFaceVars() const
303 { return curElemFaceVars_; }
304
306 const ElementFaceVariables& prevElemFaceVars() const
307 { return prevElemFaceVars_; }
308
309 CouplingManager& couplingManager()
310 { return couplingManager_; }
311
312private:
313
315 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
316 auto assembleJacobianAndResidualImpl_(Dune::index_constant<cellCenterId>, JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
317 {
318 auto& gridVariablesI = *std::get<domainId>(gridVariables);
319 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
320 const auto residual = this->asImp_().assembleCellCenterJacobianAndResidualImpl(jacRow[domainId], gridVariablesI);
321 res[cellCenterGlobalI] = residual;
322
323
324 // for the coupling blocks
325 using namespace Dune::Hybrid;
326 static constexpr auto otherDomainIds = makeIncompleteIntegerSequence<JacobianMatrixRow::size(), domainId>{};
327 forEach(otherDomainIds, [&](auto&& domainJ)
328 {
329 this->asImp_().assembleJacobianCellCenterCoupling(domainJ, jacRow[domainJ], residual, gridVariablesI);
330 });
331
332 // handle cells with a fixed Dirichlet value
333 incorporateDirichletCells_(jacRow);
334 }
335
337 template<class JacobianMatrixRow, class SubResidual, class GridVariablesTuple>
338 void assembleJacobianAndResidualImpl_(Dune::index_constant<faceId>, JacobianMatrixRow& jacRow, SubResidual& res, GridVariablesTuple& gridVariables)
339 {
340 auto& gridVariablesI = *std::get<domainId>(gridVariables);
341 const auto residual = this->asImp_().assembleFaceJacobianAndResidualImpl(jacRow[domainId], gridVariablesI);
342
343 for(auto&& scvf : scvfs(this->fvGeometry()))
344 res[scvf.dofIndex()] += residual[scvf.localFaceIdx()];
345
346 // for the coupling blocks
347 using namespace Dune::Hybrid;
348 static constexpr auto otherDomainIds = makeIncompleteIntegerSequence<JacobianMatrixRow::size(), domainId>{};
349 forEach(otherDomainIds, [&](auto&& domainJ)
350 {
351 this->asImp_().assembleJacobianFaceCoupling(domainJ, jacRow[domainJ], residual, gridVariablesI);
352 });
353 }
354
356 template<class JacobianMatrixRow>
357 void incorporateDirichletCells_(JacobianMatrixRow& jacRow)
358 {
359 const auto cellCenterGlobalI = problem().gridGeometry().elementMapper().index(this->element());
360
361 // overwrite the partial derivative with zero in case a fixed Dirichlet BC is used
362 static constexpr auto offset = numEq - numEqCellCenter;
363 for (int eqIdx = 0; eqIdx < numEqCellCenter; ++eqIdx)
364 {
365 if (problem().isDirichletCell(this->element(), this->fvGeometry(), this->fvGeometry().scv(cellCenterGlobalI), eqIdx + offset))
366 {
367 using namespace Dune::Hybrid;
368 forEach(integralRange(Dune::Hybrid::size(jacRow)), [&, domainId = domainId](auto&& i)
369 {
370 auto& ccRowI = jacRow[i][cellCenterGlobalI];
371 for (auto col = ccRowI.begin(); col != ccRowI.end(); ++col)
372 {
373 ccRowI[col.index()][eqIdx] = 0.0;
374 // set the diagonal entry to 1.0
375 if ((i == domainId) && (col.index() == cellCenterGlobalI))
376 ccRowI[col.index()][eqIdx][eqIdx] = 1.0;
377 }
378 });
379 }
380 }
381 }
382
383 ElementFaceVariables curElemFaceVars_;
384 ElementFaceVariables prevElemFaceVars_;
385 CouplingManager& couplingManager_;
386};
387
398template<std::size_t id, class TypeTag, class Assembler, class Implementation>
399class SubDomainStaggeredLocalAssemblerImplicitBase : public SubDomainStaggeredLocalAssemblerBase<id, TypeTag, Assembler, Implementation>
400{
402 static constexpr auto domainId = Dune::index_constant<id>();
403public:
404 using ParentType::ParentType;
405
407 {
408 // get some references for convenience
409 auto& couplingManager = this->couplingManager();
410 const auto& element = this->element();
411 const auto& curSol = this->curSol();
412 auto&& fvGeometry = this->fvGeometry();
413 auto&& curElemVolVars = this->curElemVolVars();
414 auto&& curElemFaceVars = this->curElemFaceVars();
415 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
416
417 // bind the caches
418 couplingManager.bindCouplingContext(domainId, element, this->assembler());
419 fvGeometry.bind(element);
423 if (!this->assembler().isStationaryProblem())
424 {
425 this->prevElemVolVars().bindElement(element, fvGeometry, this->assembler().prevSol());
426 this->prevElemFaceVars().bindElement(element, fvGeometry, this->assembler().prevSol());
427 }
428 }
429};
430
442template<std::size_t id, class TypeTag, class Assembler, DiffMethod DM = DiffMethod::numeric, bool implicit = true>
444
465template<std::size_t id, class TypeTag, class Assembler>
466class SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>
467: public SubDomainStaggeredLocalAssemblerImplicitBase<id, TypeTag, Assembler,
468 SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, true> >
469{
470 using ThisType = SubDomainStaggeredLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>;
473 using CellCenterResidualValue = typename ParentType::LocalResidual::CellCenterResidualValue;
474 using FaceResidualValue = typename ParentType::LocalResidual::FaceResidualValue;
475 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
477 using ElementFaceVariables = typename GetPropType<TypeTag, Properties::GridFaceVariables>::LocalView;
478 using FaceVariables = typename ElementFaceVariables::FaceVariables;
480 using FVElementGeometry = typename GridGeometry::LocalView;
481 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
483 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
486
488 static constexpr int maxNeighbors = 4*(2*ModelTraits::dim());
489 static constexpr auto domainI = Dune::index_constant<id>();
490 static constexpr auto cellCenterId = GridGeometry::cellCenterIdx();
491 static constexpr auto faceId = GridGeometry::faceIdx();
492
493 static constexpr auto numEq = ModelTraits::numEq();
494 static constexpr auto numEqCellCenter = CellCenterPrimaryVariables::dimension;
495 static constexpr auto numEqFace = FacePrimaryVariables::dimension;
496
497public:
499
500 CellCenterResidualValue assembleCellCenterResidualImpl()
501 {
502 return this->evalLocalResidualForCellCenter();
503 }
504
505 FaceResidualValue assembleFaceResidualImpl(const SubControlVolumeFace& scvf)
506 {
507 return this->evalLocalResidualForFace(scvf);
508 }
509
516 template<class JacobianMatrixDiagBlock, class GridVariables>
517 CellCenterResidualValue assembleCellCenterJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
518 {
519 assert(domainI == cellCenterId);
520
521 // get some aliases for convenience
522 const auto& element = this->element();
523 const auto& fvGeometry = this->fvGeometry();
524 auto&& curElemVolVars = this->curElemVolVars();
525 const auto& gridGeometry = this->problem().gridGeometry();
526 const auto& curSol = this->curSol()[domainI];
527
528 const auto cellCenterGlobalI = gridGeometry.elementMapper().index(element);
529 const auto origResidual = this->evalLocalResidualForCellCenter();
530
532 // Calculate derivatives of all cell center residuals in the element w.r.t. to other cell center dofs. //
534
535 // lambda to evaluate the derivatives for cell center dofs with respect to neighbor cells
536 auto evaluateCellCenterDerivatives = [&](const std::size_t globalJ)
537 {
538 // get the volVars of the element with respect to which we are going to build the derivative
539 auto&& scvJ = fvGeometry.scv(globalJ);
540 const auto elementJ = fvGeometry.gridGeometry().element(globalJ);
541 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
542 const auto origVolVars(curVolVars);
543
544 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
545 {
546 CellCenterPrimaryVariables cellCenterPriVars = curSol[globalJ];
547 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
548 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
549
550 constexpr auto offset = numEq - numEqCellCenter;
551
552 auto evalResidual = [&](Scalar priVar)
553 {
554 // update the volume variables
555 priVars[pvIdx + offset] = priVar;
556 auto elemSol = elementSolution<FVElementGeometry>(std::move(priVars));
557 curVolVars.update(elemSol, this->problem(), elementJ, scvJ);
558
559 // update the coupling context
560 cellCenterPriVars[pvIdx] = priVar;
561 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, cellCenterPriVars, pvIdx);
562
563 // compute element residual
564 return this->evalLocalResidualForCellCenter();
565 };
566
567 // create the vector storing the partial derivatives
568 CellCenterResidualValue partialDeriv(0.0);
569
570 // derive the residuals numerically
571 const auto& paramGroup = this->problem().paramGroup();
572 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
573 static const auto eps = this->couplingManager().numericEpsilon(domainI, paramGroup);
574 NumericDifferentiation::partialDerivative(evalResidual, priVars[pvIdx + offset], partialDeriv, origResidual,
575 eps(priVars[pvIdx + offset], pvIdx), numDiffMethod);
576
577 // update the global jacobian matrix with the current partial derivatives
578 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
579
580 // restore the original volVars
581 curVolVars = origVolVars;
582
583 // restore the undeflected state of the coupling context
584 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, curSol[globalJ], pvIdx);
585 }
586 };
587
588 // get the list of cell center dofs that have an influence on the cell center resdiual of the current element
589 const auto& connectivityMap = gridGeometry.connectivityMap();
590
591 // evaluate derivatives w.r.t. own dof
592 evaluateCellCenterDerivatives(cellCenterGlobalI);
593
594 // evaluate derivatives w.r.t. all other related cell center dofs
595 for (const auto& globalJ : connectivityMap(cellCenterId, cellCenterId, cellCenterGlobalI))
596 evaluateCellCenterDerivatives(globalJ);
597
598 return origResidual;
599 }
600
607 template<class JacobianMatrixDiagBlock, class GridVariables>
608 auto assembleFaceJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
609 {
610 assert(domainI == faceId);
611
612 // get some aliases for convenience
613 const auto& problem = this->problem();
614 const auto& element = this->element();
615 const auto& fvGeometry = this->fvGeometry();
616 const auto& gridGeometry = this->problem().gridGeometry();
617 const auto& curSol = this->curSol()[domainI];
618
619 using FaceSolutionVector = GetPropType<TypeTag, Properties::FaceSolutionVector>; // TODO: use reserved vector
620 FaceSolutionVector origResiduals;
621 origResiduals.resize(fvGeometry.numScvf());
622 origResiduals = 0.0;
623
624 // treat the local residua of the face dofs:
625 for (auto&& scvf : scvfs(fvGeometry))
626 origResiduals[scvf.localFaceIdx()] = this->evalLocalResidualForFace(scvf);
627
629 // Calculate derivatives of all face residuals in the element w.r.t. to other face dofs. //
630 // Note that we do an element-wise assembly, therefore this is only the contribution of the //
631 // current element while the contribution of the element on the opposite side of the scvf will //
632 // be added separately. //
634
635 for (auto&& scvf : scvfs(fvGeometry))
636 {
637 // set the actual dof index
638 const auto faceGlobalI = scvf.dofIndex();
639
641 const auto origFaceSolution = FaceSolution(scvf, curSol, gridGeometry);
642
643 // Lambda to evaluate the derivatives for faces
644 auto evaluateFaceDerivatives = [&](const std::size_t globalJ)
645 {
646 // get the faceVars of the face with respect to which we are going to build the derivative
647 auto& faceVars = getFaceVarAccess_(gridVariables.curGridFaceVars(), this->curElemFaceVars(), scvf);
648 const auto origFaceVars = faceVars;
649
650 for (int pvIdx = 0; pvIdx < numEqFace; ++pvIdx)
651 {
652 auto faceSolution = origFaceSolution;
653
654 auto evalResidual = [&](Scalar priVar)
655 {
656 // update the volume variables
657 faceSolution[globalJ][pvIdx] = priVar;
658 faceVars.update(faceSolution, problem, element, fvGeometry, scvf);
659
660 // update the coupling context
661 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, faceSolution[globalJ], pvIdx);
662
663 // compute face residual
664 return this->evalLocalResidualForFace(scvf);
665 };
666
667 // derive the residuals numerically
668 FaceResidualValue partialDeriv(0.0);
669 const auto& paramGroup = problem.paramGroup();
670 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
671 static const auto eps = this->couplingManager().numericEpsilon(domainI, paramGroup);
672 NumericDifferentiation::partialDerivative(evalResidual, faceSolution[globalJ][pvIdx], partialDeriv, origResiduals[scvf.localFaceIdx()],
673 eps(faceSolution[globalJ][pvIdx], pvIdx), numDiffMethod);
674
675 // update the global jacobian matrix with the current partial derivatives
676 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
677
678 // restore the original faceVars
679 faceVars = origFaceVars;
680
681 // restore the undeflected state of the coupling context
682 this->couplingManager().updateCouplingContext(domainI, *this, domainI, globalJ, origFaceSolution[globalJ], pvIdx);
683 }
684 };
685
686 // evaluate derivatives w.r.t. own dof
687 evaluateFaceDerivatives(scvf.dofIndex());
688
689 // get the list of face dofs that have an influence on the resdiual of the current face
690 const auto& connectivityMap = gridGeometry.connectivityMap();
691
692 // evaluate derivatives w.r.t. all other related face dofs
693 for (const auto& globalJ : connectivityMap(faceId, faceId, scvf.index()))
694 evaluateFaceDerivatives(globalJ);
695 }
696
697 return origResiduals;
698 }
699
704 template<class JacobianBlock, class GridVariables>
705 void assembleJacobianCellCenterCoupling(Dune::index_constant<faceId> domainJ, JacobianBlock& A,
706 const CellCenterResidualValue& origResidual, GridVariables& gridVariables)
707 {
709 // Calculate derivatives of all cell center residuals in the element w.r.t. to all coupled faces dofs //
711
712 // get some aliases for convenience
713 const auto& element = this->element();
714 const auto& fvGeometry = this->fvGeometry();
715 const auto& gridGeometry = this->problem().gridGeometry();
716 const auto& curSol = this->curSol()[domainJ];
717 // build derivatives with for cell center dofs w.r.t. cell center dofs
718 const auto cellCenterGlobalI = gridGeometry.elementMapper().index(element);
719
720 for (const auto& scvfJ : scvfs(fvGeometry))
721 {
722 const auto globalJ = scvfJ.dofIndex();
723
724 // get the faceVars of the face with respect to which we are going to build the derivative
725 auto& faceVars = getFaceVarAccess_(gridVariables.curGridFaceVars(), this->curElemFaceVars(), scvfJ);
726 const auto origFaceVars(faceVars);
727
728 for (int pvIdx = 0; pvIdx < numEqFace; ++pvIdx)
729 {
730 auto facePriVars = curSol[globalJ];
731
732 auto evalResidual = [&](Scalar priVar)
733 {
734 // update the face variables
735 facePriVars[pvIdx] = priVar;
736 faceVars.updateOwnFaceOnly(facePriVars);
737
738 // update the coupling context
739 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, facePriVars, pvIdx);
740
741 // compute element residual
742 return this->evalLocalResidualForCellCenter();
743 };
744
745 // create the vector storing the partial derivatives
746 CellCenterResidualValue partialDeriv(0.0);
747
748 // derive the residuals numerically
749 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
750 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
751 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
752 NumericDifferentiation::partialDerivative(evalResidual, facePriVars[pvIdx], partialDeriv, origResidual,
753 epsCoupl(facePriVars[pvIdx], pvIdx), numDiffMethod);
754
755 // update the global jacobian matrix with the current partial derivatives
756 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
757
758 // restore the original faceVars
759 faceVars = origFaceVars;
760
761 // restore the undeflected state of the coupling context
762 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, curSol[globalJ], pvIdx);
763 }
764 }
765 }
766
767 template<std::size_t otherId, class JacobianBlock, class GridVariables>
768 void assembleJacobianCellCenterCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
769 const CellCenterResidualValue& res, GridVariables& gridVariables)
770 {
772 // Calculate derivatives of all cell center residuals in the element w.r.t. all dofs in the coupling stencil. //
774
775 // get some aliases for convenience
776 const auto& element = this->element();
777
778 // get stencil information
779 const auto& stencil = this->couplingManager().couplingStencil(domainI, element, domainJ);
780
781 if (stencil.empty())
782 return;
783
784 for (const auto globalJ : stencil)
785 {
786 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
787 const auto& curSol = this->curSol()[domainJ];
788 const auto origPriVarsJ = curSol[globalJ];
789
790 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
791 {
792 auto evalCouplingResidual = [&](Scalar priVar)
793 {
794 auto deflectedPriVarsJ = origPriVarsJ;
795 deflectedPriVarsJ[pvIdx] = priVar;
796 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedPriVarsJ, pvIdx);
797 return this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
798 };
799
800 // create the vector storing the partial derivatives
801 CellCenterResidualValue partialDeriv(0.0);
802
803 // derive the residuals numerically
804 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
805 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
806 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
807 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDeriv, origResidual,
808 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
809
810 // update the global stiffness matrix with the current partial derivatives
811 const auto cellCenterGlobalI = this->problem().gridGeometry().elementMapper().index(element);
812 updateGlobalJacobian_(A, cellCenterGlobalI, globalJ, pvIdx, partialDeriv);
813
814 // restore the undeflected state of the coupling context
815 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origPriVarsJ, pvIdx);
816 }
817 }
818 }
819
824 template<class JacobianBlock, class ElementResidualVector, class GridVariables>
825 void assembleJacobianFaceCoupling(Dune::index_constant<cellCenterId> domainJ, JacobianBlock& A,
826 const ElementResidualVector& origResiduals, GridVariables& gridVariables)
827 {
829 // Calculate derivatives of all face residuals in the element w.r.t. all coupled cell center dofs //
831
832 // get some aliases for convenience
833 const auto& problem = this->problem();
834 const auto& fvGeometry = this->fvGeometry();
835 const auto& gridGeometry = this->problem().gridGeometry();
836 const auto& connectivityMap = gridGeometry.connectivityMap();
837 const auto& curSol = this->curSol()[domainJ];
838
839 // build derivatives with for cell center dofs w.r.t. cell center dofs
840 for (auto&& scvf : scvfs(fvGeometry))
841 {
842 // set the actual dof index
843 const auto faceGlobalI = scvf.dofIndex();
844
845 // build derivatives with for face dofs w.r.t. cell center dofs
846 for (const auto& globalJ : connectivityMap(faceId, cellCenterId, scvf.index()))
847 {
848 // get the volVars of the element with respect to which we are going to build the derivative
849 auto&& scvJ = fvGeometry.scv(globalJ);
850 const auto elementJ = fvGeometry.gridGeometry().element(globalJ);
851 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), this->curElemVolVars(), scvJ);
852 const auto origVolVars(curVolVars);
853 const auto origCellCenterPriVars = curSol[globalJ];
854
855 for (int pvIdx = 0; pvIdx < numEqCellCenter; ++pvIdx)
856 {
857 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
858 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(origCellCenterPriVars);
859
860 constexpr auto offset = PrimaryVariables::dimension - CellCenterPrimaryVariables::dimension;
861
862 auto evalResidual = [&](Scalar priVar)
863 {
864 // update the volume variables
865 priVars[pvIdx + offset] = priVar;
866 auto elemSol = elementSolution<FVElementGeometry>(std::move(priVars));
867 curVolVars.update(elemSol, problem, elementJ, scvJ);
868
869 // update the coupling context
870 auto deflectedCellCenterPriVars = origCellCenterPriVars;
871 deflectedCellCenterPriVars[pvIdx] = priVar;
872 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedCellCenterPriVars, pvIdx);
873
874 // compute face residual
875 return this->evalLocalResidualForFace(scvf);
876 };
877
878 // derive the residuals numerically
879 FaceResidualValue partialDeriv(0.0);
880 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
881 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
882 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
883 NumericDifferentiation::partialDerivative(evalResidual, priVars[pvIdx + offset], partialDeriv, origResiduals[scvf.localFaceIdx()],
884 epsCoupl(priVars[pvIdx + offset], pvIdx), numDiffMethod);
885
886 // update the global jacobian matrix with the current partial derivatives
887 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
888
889 // restore the original volVars
890 curVolVars = origVolVars;
891
892 // restore the undeflected state of the coupling context
893 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origCellCenterPriVars, pvIdx);
894 }
895 }
896 }
897 }
898
899 template<std::size_t otherId, class JacobianBlock, class ElementResidualVector, class GridVariables>
900 void assembleJacobianFaceCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
901 const ElementResidualVector& res, GridVariables& gridVariables)
902 {
904 // Calculate derivatives of all face residuals in the element w.r.t. all dofs in the coupling stencil. //
906
907 // get some aliases for convenience
908 const auto& fvGeometry = this->fvGeometry();
909 const auto& curSol = this->curSol()[domainJ];
910
911 // build derivatives with for cell center dofs w.r.t. cell center dofs
912 for (auto&& scvf : scvfs(fvGeometry))
913 {
914 // set the actual dof index
915 const auto faceGlobalI = scvf.dofIndex();
916
917 // get stencil information
918 const auto& stencil = this->couplingManager().couplingStencil(domainI, scvf, domainJ);
919
920 if (stencil.empty())
921 continue;
922
923 // build derivatives with for face dofs w.r.t. cell center dofs
924 for (const auto& globalJ : stencil)
925 {
926 const auto origPriVarsJ = curSol[globalJ];
927 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, scvf, *this, domainJ, globalJ);
928
929 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
930 {
931 auto evalCouplingResidual = [&](Scalar priVar)
932 {
933 auto deflectedPriVars = origPriVarsJ;
934 deflectedPriVars[pvIdx] = priVar;
935 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, deflectedPriVars, pvIdx);
936 return this->couplingManager().evalCouplingResidual(domainI, scvf, *this, domainJ, globalJ);
937 };
938
939 // derive the residuals numerically
940 FaceResidualValue partialDeriv(0.0);
941 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
942 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
943 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
944 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDeriv, origResidual,
945 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
946
947 // update the global stiffness matrix with the current partial derivatives
948 updateGlobalJacobian_(A, faceGlobalI, globalJ, pvIdx, partialDeriv);
949
950 // restore the undeflected state of the coupling context
951 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, origPriVarsJ, pvIdx);
952 }
953 }
954 }
955 }
956
957 template<class JacobianMatrixDiagBlock, class GridVariables>
958 void evalAdditionalDerivatives(const std::vector<std::size_t>& additionalDofDependencies,
959 JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
960 { }
961
967 template<class SubMatrix, class CCOrFacePrimaryVariables>
968 static void updateGlobalJacobian_(SubMatrix& matrix,
969 const int globalI,
970 const int globalJ,
971 const int pvIdx,
972 const CCOrFacePrimaryVariables& partialDeriv)
973 {
974 for (int eqIdx = 0; eqIdx < partialDeriv.size(); eqIdx++)
975 {
976 // A[i][col][eqIdx][pvIdx] is the rate of change of
977 // the residual of equation 'eqIdx' at dof 'i'
978 // depending on the primary variable 'pvIdx' at dof
979 // 'col'.
980
981 assert(pvIdx >= 0);
982 assert(eqIdx < matrix[globalI][globalJ].size());
983 assert(pvIdx < matrix[globalI][globalJ][eqIdx].size());
984 matrix[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
985 }
986 }
987
988private:
989
990 FaceVariables& getFaceVarAccess_(GridFaceVariables& gridFaceVariables, ElementFaceVariables& elemFaceVars, const SubControlVolumeFace& scvf)
991 {
993 return gridFaceVariables.faceVars(scvf.index());
994 else
995 return elemFaceVars[scvf];
996 }
997};
998
999} // end namespace Dumux
1000
1001#endif
A base class for all local assemblers.
Definition: assembly/fvlocalassemblerbase.hh:36
ElementVolumeVariables & curElemVolVars()
The current element volume variables.
Definition: assembly/fvlocalassemblerbase.hh:253
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: assembly/fvlocalassemblerbase.hh:56
ElementBoundaryTypes & elemBcTypes()
The element's boundary types.
Definition: assembly/fvlocalassemblerbase.hh:269
Implementation & asImp_()
Definition: assembly/fvlocalassemblerbase.hh:297
ElementVolumeVariables & prevElemVolVars()
The element volume variables of the provious time step.
Definition: assembly/fvlocalassemblerbase.hh:257
FVElementGeometry & fvGeometry()
The global finite volume geometry.
Definition: assembly/fvlocalassemblerbase.hh:249
const Assembler & assembler() const
The assembler.
Definition: assembly/fvlocalassemblerbase.hh:233
ElementFluxVariablesCache & elemFluxVarsCache()
The element flux variables cache.
Definition: assembly/fvlocalassemblerbase.hh:261
bool elementIsGhost() const
Returns if element is a ghost entity.
Definition: assembly/fvlocalassemblerbase.hh:241
LocalResidual & localResidual()
The local residual for the current element.
Definition: assembly/fvlocalassemblerbase.hh:265
static constexpr bool isImplicit()
Returns true if the assembler considers implicit assembly.
Definition: assembly/fvlocalassemblerbase.hh:101
const Element & element() const
The current element.
Definition: assembly/fvlocalassemblerbase.hh:237
const SolutionVector & curSol() const
The current solution.
Definition: assembly/fvlocalassemblerbase.hh:245
static void partialDerivative(const Function &function, Scalar x0, FunctionEvalType &derivative, const FunctionEvalType &fx0, const int numericDifferenceMethod=1)
Computes the derivative of a function with respect to a function parameter.
Definition: numericdifferentiation.hh:49
Staggered scheme local assembler using numeric differentiation and implicit time discretization.
Definition: subdomainstaggeredlocalassembler.hh:469
void assembleJacobianFaceCoupling(Dune::index_constant< cellCenterId > domainJ, JacobianBlock &A, const ElementResidualVector &origResiduals, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: subdomainstaggeredlocalassembler.hh:825
void assembleJacobianFaceCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const ElementResidualVector &res, GridVariables &gridVariables)
Definition: subdomainstaggeredlocalassembler.hh:900
FaceResidualValue assembleFaceResidualImpl(const SubControlVolumeFace &scvf)
Definition: subdomainstaggeredlocalassembler.hh:505
CellCenterResidualValue assembleCellCenterJacobianAndResidualImpl(JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: subdomainstaggeredlocalassembler.hh:517
void assembleJacobianCellCenterCoupling(Dune::index_constant< faceId > domainJ, JacobianBlock &A, const CellCenterResidualValue &origResidual, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: subdomainstaggeredlocalassembler.hh:705
CellCenterResidualValue assembleCellCenterResidualImpl()
Definition: subdomainstaggeredlocalassembler.hh:500
static void updateGlobalJacobian_(SubMatrix &matrix, const int globalI, const int globalJ, const int pvIdx, const CCOrFacePrimaryVariables &partialDeriv)
Updates the current global Jacobian matrix with the partial derivatives of all equations in regard to...
Definition: subdomainstaggeredlocalassembler.hh:968
void evalAdditionalDerivatives(const std::vector< std::size_t > &additionalDofDependencies, JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Definition: subdomainstaggeredlocalassembler.hh:958
auto assembleFaceJacobianAndResidualImpl(JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: subdomainstaggeredlocalassembler.hh:608
void assembleJacobianCellCenterCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const CellCenterResidualValue &res, GridVariables &gridVariables)
Definition: subdomainstaggeredlocalassembler.hh:768
A base class for all multidomain local assemblers (staggered)
Definition: subdomainstaggeredlocalassembler.hh:46
FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace &scvf) const
Convenience function to evaluate the local residual for the current face. Automatically chooses the t...
Definition: subdomainstaggeredlocalassembler.hh:216
const ElementFaceVariables & curElemFaceVars() const
The current element volume variables.
Definition: subdomainstaggeredlocalassembler.hh:302
FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace &scvf, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars) const
Evaluates the flux and source terms (i.e, the terms without a time derivative) of the local residual ...
Definition: subdomainstaggeredlocalassembler.hh:272
ElementFaceVariables & prevElemFaceVars()
The element volume variables of the provious time step.
Definition: subdomainstaggeredlocalassembler.hh:298
static constexpr auto domainId
Definition: subdomainstaggeredlocalassembler.hh:72
const Problem & problem() const
Definition: subdomainstaggeredlocalassembler.hh:290
SubDomainStaggeredLocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol, CouplingManager &couplingManager)
Definition: subdomainstaggeredlocalassembler.hh:81
FaceResidualValue evalLocalFluxAndSourceResidualForFace(const SubControlVolumeFace &scvf) const
Convenience function to evaluate the flux and source terms (i.e, the terms without a time derivative)...
Definition: subdomainstaggeredlocalassembler.hh:259
CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter() const
Convenience function to evaluate the flux and source terms (i.e, the terms without a time derivative)...
Definition: subdomainstaggeredlocalassembler.hh:183
static constexpr auto faceId
Definition: subdomainstaggeredlocalassembler.hh:74
static constexpr auto faceOffset
Definition: subdomainstaggeredlocalassembler.hh:77
FaceResidualValue evalLocalResidualForFace(const SubControlVolumeFace &scvf, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars) const
Evaluates the complete local residual for the current face.
Definition: subdomainstaggeredlocalassembler.hh:237
static constexpr auto numEqCellCenter
Definition: subdomainstaggeredlocalassembler.hh:76
const ElementFaceVariables & prevElemFaceVars() const
The element volume variables of the provious time step.
Definition: subdomainstaggeredlocalassembler.hh:306
CellCenterResidualValue evalLocalResidualForCellCenter() const
Convenience function to evaluate the complete local residual for the current element....
Definition: subdomainstaggeredlocalassembler.hh:137
FaceResidualValue evalLocalStorageResidualForFace(const SubControlVolumeFace &scvf) const
Convenience function to evaluate storage term (i.e, the term with a time derivative) of the local res...
Definition: subdomainstaggeredlocalassembler.hh:285
CouplingManager & couplingManager()
Definition: subdomainstaggeredlocalassembler.hh:309
static constexpr auto cellCenterId
Definition: subdomainstaggeredlocalassembler.hh:73
CellCenterResidualValue evalLocalResidualForCellCenter(const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars) const
Evaluates the complete local residual for the current cell center.
Definition: subdomainstaggeredlocalassembler.hh:157
void assembleJacobianAndResidual(JacobianMatrixRow &jacRow, SubResidual &res, GridVariablesTuple &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition: subdomainstaggeredlocalassembler.hh:104
CellCenterResidualValue evalLocalFluxAndSourceResidualForCellCenter(const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars) const
Evaluates the flux and source terms (i.e, the terms without a time derivative) of the local residual ...
Definition: subdomainstaggeredlocalassembler.hh:196
CellCenterResidualValue evalLocalStorageResidualForCellCenter() const
Convenience function to evaluate storage term (i.e, the term with a time derivative) of the local res...
Definition: subdomainstaggeredlocalassembler.hh:206
void assembleResidual(SubResidual &res)
Assemble the residual only.
Definition: subdomainstaggeredlocalassembler.hh:116
ElementFaceVariables & curElemFaceVars()
The current element volume variables.
Definition: subdomainstaggeredlocalassembler.hh:294
The staggered multidomain local assembler.
Definition: subdomainstaggeredlocalassembler.hh:443
A base class for all implicit multidomain local assemblers (staggered)
Definition: subdomainstaggeredlocalassembler.hh:400
void bindLocalViews()
Definition: subdomainstaggeredlocalassembler.hh:406
Defines all properties used in Dumux.
An enum class to define various differentiation methods available in order to compute the derivatives...
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition: diffmethod.hh:25
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Definition: adapt.hh:17
typename Detail::ConcatSeq< decltype(std::make_index_sequence< e >{}), e+1, decltype(std::make_index_sequence<(n > e) ?(n - e - 1) :0 >{})>::type makeIncompleteIntegerSequence
Definition: utility.hh:59
Definition: common/pdesolver.hh:24
A class for numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
A arithmetic block vector type based on DUNE's reserved vector.
The local element solution class for staggered methods.
Utilities for template meta programming.