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