3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
Loading...
Searching...
No Matches
subdomainboxlocalassembler.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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
26#ifndef DUMUX_MULTIDOMAIN_BOX_LOCAL_ASSEMBLER_HH
27#define DUMUX_MULTIDOMAIN_BOX_LOCAL_ASSEMBLER_HH
28
29#include <dune/common/reservedvector.hh>
30#include <dune/common/indices.hh>
31#include <dune/common/hybridutilities.hh>
32#include <dune/grid/common/gridenums.hh> // for GhostEntity
33#include <dune/istl/matrixindexset.hh>
34
44
45namespace Dumux {
46
58template<std::size_t id, class TypeTag, class Assembler, class Implementation, bool implicit>
59class SubDomainBoxLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
60{
62
65 using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector;
67 using SolutionVector = typename Assembler::SolutionVector;
70
72 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
73 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
74 using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
75 using Scalar = typename GridVariables::Scalar;
76
77 using GridGeometry = typename GridVariables::GridGeometry;
78 using FVElementGeometry = typename GridGeometry::LocalView;
79 using SubControlVolume = typename GridGeometry::SubControlVolume;
80 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
81 using Extrusion = Extrusion_t<GridGeometry>;
82 using GridView = typename GridGeometry::GridView;
83 using Element = typename GridView::template Codim<0>::Entity;
84
85 using CouplingManager = typename Assembler::CouplingManager;
86
87 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
88
89public:
91 static constexpr auto domainId = typename Dune::index_constant<id>();
93 using ParentType::ParentType;
94
95 // the constructor
96 explicit SubDomainBoxLocalAssemblerBase(const Assembler& assembler,
97 const Element& element,
98 const SolutionVector& curSol,
99 CouplingManager& couplingManager)
100 : ParentType(assembler,
101 element,
102 curSol,
103 localView(assembler.gridGeometry(domainId)),
104 localView(assembler.gridVariables(domainId).curGridVolVars()),
105 localView(assembler.gridVariables(domainId).prevGridVolVars()),
106 localView(assembler.gridVariables(domainId).gridFluxVarsCache()),
108 (element.partitionType() == Dune::GhostEntity))
109 , couplingManager_(couplingManager)
110 {}
111
116 template<class JacobianMatrixRow, class GridVariablesTuple>
117 void assembleJacobianAndResidual(JacobianMatrixRow& jacRow, SubSolutionVector& res, GridVariablesTuple& gridVariables)
118 {
119 this->asImp_().bindLocalViews();
120 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
121
122 if (!this->elementIsGhost())
123 {
124 // for the diagonal jacobian block
125 // forward to the internal implementation
126 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jacRow[domainId], *std::get<domainId>(gridVariables));
127
128 // update the residual vector
129 for (const auto& scv : scvs(this->fvGeometry()))
130 res[scv.dofIndex()] += residual[scv.localDofIndex()];
131
132 // assemble the coupling blocks
133 using namespace Dune::Hybrid;
134 forEach(integralRange(Dune::Hybrid::size(jacRow)), [&](auto&& i)
135 {
136 if (i != id)
137 this->assembleJacobianCoupling(i, jacRow, residual, gridVariables);
138 });
139 }
140 else
141 {
142 using GridGeometry = typename GridVariables::GridGeometry;
143 using GridView = typename GridGeometry::GridView;
144 static constexpr auto dim = GridView::dimension;
145
146 int numVerticesLocal = this->element().subEntities(dim);
147
148 for (int i = 0; i < numVerticesLocal; ++i)
149 {
150 const auto vertex = this->element().template subEntity<dim>(i);
151
152 if (vertex.partitionType() == Dune::InteriorEntity ||
153 vertex.partitionType() == Dune::BorderEntity)
154 {
155 // do not change the non-ghost vertices
156 continue;
157 }
158
159 // set main diagonal entries for the vertex
160 const auto vIdx = this->assembler().gridGeometry(domainId).vertexMapper().index(vertex);
161
162 typedef typename JacobianMatrix::block_type BlockType;
163 BlockType &J = jacRow[domainId][vIdx][vIdx];
164 for (int j = 0; j < BlockType::rows; ++j)
165 J[j][j] = 1.0;
166
167 // set residual for the vertex
168 res[vIdx] = 0;
169 }
170 }
171
172 // lambda for the incorporation of Dirichlet Bcs
173 auto applyDirichlet = [&] (const auto& scvI,
174 const auto& dirichletValues,
175 const auto eqIdx,
176 const auto pvIdx)
177 {
178 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
179
180 // in explicit schemes we only have entries on the diagonal
181 // and thus don't have to do anything with off-diagonal entries
182 if (implicit)
183 {
184 for (const auto& scvJ : scvs(this->fvGeometry()))
185 jacRow[domainId][scvI.dofIndex()][scvJ.dofIndex()][eqIdx] = 0.0;
186 }
187
188 jacRow[domainId][scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
189 };
190
191 // incorporate Dirichlet BCs
192 this->asImp_().enforceDirichletConstraints(applyDirichlet);
193 }
194
199 template<std::size_t otherId, class JacRow, class GridVariables,
200 typename std::enable_if_t<(otherId == id), int> = 0>
201 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow,
202 const ElementResidualVector& res, GridVariables& gridVariables)
203 {}
204
208 template<std::size_t otherId, class JacRow, class GridVariables,
209 typename std::enable_if_t<(otherId != id), int> = 0>
210 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow,
211 const ElementResidualVector& res, GridVariables& gridVariables)
212 {
213 this->asImp_().assembleJacobianCoupling(domainJ, jacRow[domainJ], res, *std::get<domainId>(gridVariables));
214 }
215
219 void assembleResidual(SubSolutionVector& res)
220 {
221 this->asImp_().bindLocalViews();
222 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
223
224 const auto residual = this->evalLocalResidual();
225 for (const auto& scv : scvs(this->fvGeometry()))
226 res[scv.dofIndex()] += residual[scv.localDofIndex()];
227
228 auto applyDirichlet = [&] (const auto& scvI,
229 const auto& dirichletValues,
230 const auto eqIdx,
231 const auto pvIdx)
232 {
233 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
234 };
235
236 this->asImp_().enforceDirichletConstraints(applyDirichlet);
237 }
238
242 ElementResidualVector evalLocalSourceResidual(const Element& element, const ElementVolumeVariables& elemVolVars) const
243 {
244 // initialize the residual vector for all scvs in this element
245 ElementResidualVector residual(this->fvGeometry().numScv());
246
247 // evaluate the volume terms (storage + source terms)
248 // forward to the local residual specialized for the discretization methods
249 for (auto&& scv : scvs(this->fvGeometry()))
250 {
251 const auto& curVolVars = elemVolVars[scv];
252 auto source = this->localResidual().computeSource(problem(), element, this->fvGeometry(), elemVolVars, scv);
253 source *= -Extrusion::volume(scv)*curVolVars.extrusionFactor();
254 residual[scv.localDofIndex()] = std::move(source);
255 }
256
257 return residual;
258 }
259
263 ElementResidualVector evalLocalSourceResidual(const Element& neighbor) const
264 { return this->evalLocalSourceResidual(neighbor, implicit ? this->curElemVolVars() : this->prevElemVolVars()); }
265
267 template<typename ApplyFunction>
268 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
269 {
270 // enforce Dirichlet boundary conditions
271 this->asImp_().evalDirichletBoundaries(applyDirichlet);
272 // take care of internal Dirichlet constraints (if enabled)
273 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
274 }
275
280 template< typename ApplyDirichletFunctionType >
281 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
282 {
283 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
284 // and set the residual to (privar - dirichletvalue)
285 if (this->elemBcTypes().hasDirichlet())
286 {
287 for (const auto& scvI : scvs(this->fvGeometry()))
288 {
289 const auto bcTypes = this->elemBcTypes()[scvI.localDofIndex()];
290 if (bcTypes.hasDirichlet())
291 {
292 const auto dirichletValues = this->problem().dirichlet(this->element(), scvI);
293
294 // set the dirichlet conditions in residual and jacobian
295 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
296 {
297 if (bcTypes.isDirichlet(eqIdx))
298 {
299 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
300 assert(0 <= pvIdx && pvIdx < numEq);
301 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
302 }
303 }
304 }
305 }
306 }
307 }
308
313 {
314 // get some references for convenience
315 const auto& element = this->element();
316 const auto& curSol = this->curSol()[domainId];
317 auto&& fvGeometry = this->fvGeometry();
318 auto&& curElemVolVars = this->curElemVolVars();
319 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
320
321 // bind the caches
322 couplingManager_.bindCouplingContext(domainId, element, this->assembler());
323 fvGeometry.bind(element);
324
325 if (implicit)
326 {
329 if (!this->assembler().isStationaryProblem())
330 this->prevElemVolVars().bindElement(element, fvGeometry, this->assembler().prevSol()[domainId]);
331 }
332 else
333 {
334 auto& prevElemVolVars = this->prevElemVolVars();
335 const auto& prevSol = this->assembler().prevSol()[domainId];
336
338 prevElemVolVars.bind(element, fvGeometry, prevSol);
340 }
341 }
342
344 const Problem& problem() const
345 { return this->assembler().problem(domainId); }
346
348 CouplingManager& couplingManager()
349 { return couplingManager_; }
350
351private:
352 CouplingManager& couplingManager_;
353};
354
366template<std::size_t id, class TypeTag, class Assembler, DiffMethod DM = DiffMethod::numeric, bool implicit = true>
368
375template<std::size_t id, class TypeTag, class Assembler>
376class SubDomainBoxLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>
377: public SubDomainBoxLocalAssemblerBase<id, TypeTag, Assembler,
379{
380 using ThisType = SubDomainBoxLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>;
381 using ParentType = SubDomainBoxLocalAssemblerBase<id, TypeTag, Assembler, ThisType, /*implicit=*/true>;
384 using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector;
385
386 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
388 using FVElementGeometry = typename GridGeometry::LocalView;
389 using GridView = typename GridGeometry::GridView;
390 using Element = typename GridView::template Codim<0>::Entity;
392
394 enum { dim = GridView::dimension };
395
396 static constexpr bool enableGridFluxVarsCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
397 static constexpr bool enableGridVolVarsCache = getPropValue<TypeTag, Properties::EnableGridVolumeVariablesCache>();
398 static constexpr auto domainI = Dune::index_constant<id>();
399
400public:
401 using ParentType::ParentType;
402
409 template<class JacobianMatrixDiagBlock, class GridVariables>
410 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
411 {
413 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
414 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
415 // actual element. In the actual element we evaluate the derivative of the entire residual. //
417
418 // get the vecor of the acutal element residuals
419 const auto origResiduals = this->evalLocalResidual();
420
422 // compute the derivatives of this element with respect to all of the element's dofs and add them to the Jacobian //
424 const auto& element = this->element();
425 const auto& fvGeometry = this->fvGeometry();
426 const auto& curSol = this->curSol()[domainI];
427 auto&& curElemVolVars = this->curElemVolVars();
428
429 // create the element solution
430 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
431
432 auto partialDerivs = origResiduals;
433 partialDerivs = 0.0;
434
435 for (auto&& scv : scvs(fvGeometry))
436 {
437 // dof index and corresponding actual pri vars
438 const auto dofIdx = scv.dofIndex();
439 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
440 const VolumeVariables origVolVars(curVolVars);
441
442 // calculate derivatives w.r.t to the privars at the dof at hand
443 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
444 {
445 partialDerivs = 0.0;
446
447 auto evalResiduals = [&](Scalar priVar)
448 {
449 // update the volume variables and compute element residual
450 const auto localDofIndex = scv.localDofIndex();
451 elemSol[localDofIndex][pvIdx] = priVar;
452 curVolVars.update(elemSol, this->problem(), element, scv);
453 this->couplingManager().updateCouplingContext(domainI, *this, domainI, scv.dofIndex(), elemSol[localDofIndex], pvIdx);
454 return this->evalLocalResidual();
455 };
456
457 // derive the residuals numerically
458 static const int numDiffMethod = getParamFromGroup<int>(this->problem().paramGroup(), "Assembly.NumericDifferenceMethod");
459 static const NumericEpsilon<Scalar, numEq> eps_{this->problem().paramGroup()};
460 NumericDifferentiation::partialDerivative(evalResiduals, elemSol[scv.localDofIndex()][pvIdx], partialDerivs, origResiduals,
461 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
462
463 // update the global stiffness matrix with the current partial derivatives
464 for (auto&& scvJ : scvs(fvGeometry))
465 {
466 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
467 {
468 // A[i][col][eqIdx][pvIdx] is the rate of change of
469 // the residual of equation 'eqIdx' at dof 'i'
470 // depending on the primary variable 'pvIdx' at dof
471 // 'col'.
472 A[scvJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[scvJ.localDofIndex()][eqIdx];
473 }
474 }
475
476 // restore the original state of the scv's volume variables
477 curVolVars = origVolVars;
478
479 // restore the original element solution and coupling context
480 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
481 this->couplingManager().updateCouplingContext(domainI, *this, domainI, scv.dofIndex(), elemSol[scv.localDofIndex()], pvIdx);
482 }
483 }
484
485 // evaluate additional derivatives that might arise from the coupling
486 this->couplingManager().evalAdditionalDomainDerivatives(domainI, *this, origResiduals, A, gridVariables);
487
488 return origResiduals;
489 }
490
495 template<std::size_t otherId, class JacobianBlock, class GridVariables>
496 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
497 const ElementResidualVector& res, GridVariables& gridVariables)
498 {
500 // Calculate derivatives of all dofs in the element with respect to all dofs in the coupling stencil. //
502
503 // get some aliases for convenience
504 const auto& element = this->element();
505 const auto& fvGeometry = this->fvGeometry();
506 auto&& curElemVolVars = this->curElemVolVars();
507 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
508
509 // get element stencil informations
510 const auto& stencil = this->couplingManager().couplingStencil(domainI, element, domainJ);
511
512 // convenience lambda for call to update self
513 auto updateCoupledVariables = [&] ()
514 {
515 // Update ourself after the context has been modified. Depending on the
516 // type of caching, other objects might have to be updated. All ifs can be optimized away.
517 if (enableGridFluxVarsCache)
518 {
519 if (enableGridVolVarsCache)
520 this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), gridVariables.gridFluxVarsCache());
521 else
522 this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, gridVariables.gridFluxVarsCache());
523 }
524 else
525 {
526 if (enableGridVolVarsCache)
527 this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), elemFluxVarsCache);
528 else
529 this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, elemFluxVarsCache);
530 }
531 };
532
533 const auto& curSolJ = this->curSol()[domainJ];
534 for (const auto globalJ : stencil)
535 {
536 // undeflected privars and privars to be deflected
537 const auto origPriVarsJ = curSolJ[globalJ];
538 auto priVarsJ = origPriVarsJ;
539
540 // the undeflected coupling residual
541 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
542
543 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
544 {
545 auto evalCouplingResidual = [&](Scalar priVar)
546 {
547 priVarsJ[pvIdx] = priVar;
548 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx);
549 updateCoupledVariables();
550 return this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
551 };
552
553 // derive the residuals numerically
554 ElementResidualVector partialDerivs(element.subEntities(dim));
555
556 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
557 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
558 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
559
560 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDerivs, origResidual,
561 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
562
563 // update the global stiffness matrix with the current partial derivatives
564 for (auto&& scv : scvs(fvGeometry))
565 {
566 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
567 {
568 // A[i][col][eqIdx][pvIdx] is the rate of change of
569 // the residual of equation 'eqIdx' at dof 'i'
570 // depending on the primary variable 'pvIdx' at dof
571 // 'col'.
572
573 // If the dof is coupled by a Dirichlet condition,
574 // set the derived value only once (i.e. overwrite existing values).
575 // For other dofs, add the contribution of the partial derivative.
576 const auto bcTypes = this->elemBcTypes()[scv.localDofIndex()];
577 if (bcTypes.isCouplingDirichlet(eqIdx))
578 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = partialDerivs[scv.localDofIndex()][eqIdx];
579 else if (bcTypes.isDirichlet(eqIdx))
580 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0;
581 else
582 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
583
584 // enforce internal Dirichlet constraints
585 if constexpr (Problem::enableInternalDirichletConstraints())
586 {
587 const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
588 if (internalDirichletConstraints[eqIdx])
589 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0;
590 }
591
592 }
593 }
594
595 // restore the current element solution
596 priVarsJ[pvIdx] = origPriVarsJ[pvIdx];
597
598 // restore the undeflected state of the coupling context
599 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx);
600 }
601
602 // Restore original state of the flux vars cache and/or vol vars.
603 // This has to be done in case they depend on variables of domainJ before
604 // we continue with the numeric derivative w.r.t the next globalJ. Otherwise,
605 // the next "origResidual" will be incorrect.
606 updateCoupledVariables();
607 }
608 }
609};
610
617template<std::size_t id, class TypeTag, class Assembler>
618class SubDomainBoxLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>
619: public SubDomainBoxLocalAssemblerBase<id, TypeTag, Assembler,
620 SubDomainBoxLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, false>, false >
621{
622 using ThisType = SubDomainBoxLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>;
623 using ParentType = SubDomainBoxLocalAssemblerBase<id, TypeTag, Assembler, ThisType, /*implicit=*/false>;
626 using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector;
627 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
629 using FVElementGeometry = typename GridGeometry::LocalView;
630 using GridView = typename GridGeometry::GridView;
631 using Element = typename GridView::template Codim<0>::Entity;
632
634 enum { dim = GridView::dimension };
635
636 static constexpr bool enableGridFluxVarsCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
637 static constexpr bool enableGridVolVarsCache = getPropValue<TypeTag, Properties::EnableGridVolumeVariablesCache>();
638 static constexpr auto domainI = Dune::index_constant<id>();
639
640public:
641 using ParentType::ParentType;
642
649 template<class JacobianMatrixDiagBlock, class GridVariables>
650 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
651 {
652 if (this->assembler().isStationaryProblem())
653 DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
654
655 // get some aliases for convenience
656 const auto& element = this->element();
657 const auto& fvGeometry = this->fvGeometry();
658 const auto& curSol = this->curSol()[domainI];
659 auto&& curElemVolVars = this->curElemVolVars();
660
661 // get the vector of the actual (undeflected) element residuals
662 const auto origResiduals = this->evalLocalResidual();
663 const auto origStorageResiduals = this->evalLocalStorageResidual();
664
666 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
667 // neighboring elements all derivatives are zero. For the assembled element only the storage //
668 // derivatives are non-zero. //
670
671 // create the element solution
672 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
673
674 // create the vector storing the partial derivatives
675 ElementResidualVector partialDerivs(element.subEntities(dim));
676
677 // calculation of the derivatives
678 for (auto&& scv : scvs(fvGeometry))
679 {
680 // dof index and corresponding actual pri vars
681 const auto dofIdx = scv.dofIndex();
682 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
683 const VolumeVariables origVolVars(curVolVars);
684
685 // calculate derivatives w.r.t to the privars at the dof at hand
686 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
687 {
688 partialDerivs = 0.0;
689
690 auto evalStorage = [&](Scalar priVar)
691 {
692 // auto partialDerivsTmp = partialDerivs;
693 elemSol[scv.localDofIndex()][pvIdx] = priVar;
694 curVolVars.update(elemSol, this->problem(), element, scv);
695 return this->evalLocalStorageResidual();
696 };
697
698 // derive the residuals numerically
699 static const NumericEpsilon<Scalar, numEq> eps_{this->problem().paramGroup()};
700 static const int numDiffMethod = getParamFromGroup<int>(this->problem().paramGroup(), "Assembly.NumericDifferenceMethod");
701 NumericDifferentiation::partialDerivative(evalStorage, elemSol[scv.localDofIndex()][pvIdx], partialDerivs, origStorageResiduals,
702 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
703
704 // update the global stiffness matrix with the current partial derivatives
705 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
706 {
707 // A[i][col][eqIdx][pvIdx] is the rate of change of
708 // the residual of equation 'eqIdx' at dof 'i'
709 // depending on the primary variable 'pvIdx' at dof
710 // 'col'.
711 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
712 }
713
714 // restore the original state of the scv's volume variables
715 curVolVars = origVolVars;
716
717 // restore the original element solution
718 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
719 // TODO additional dof dependencies
720 }
721 }
722
723 // return the undeflected residual
724 return origResiduals;
725 }
726
733 template<std::size_t otherId, class JacobianBlock, class GridVariables>
734 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
735 const ElementResidualVector& res, GridVariables& gridVariables)
736 {}
737};
738
739} // end namespace Dumux
740
741#endif
A helper to deduce a vector with the same size as numbers of equations.
A class for numeric differentiation.
A arithmetic block vector type based on DUNE's reserved vector.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
A base class for all local assemblers.
An adapter class for local assemblers using numeric differentiation.
An enum class to define various differentiation methods available in order to compute the derivatives...
Helper classes to compute the integration elements.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition localview.hh:38
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::box, BoxElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for box schemes.
Definition box/elementsolution.hh:118
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition diffmethod.hh:37
@ numeric
Definition diffmethod.hh:38
typename NumEqVectorTraits< PrimaryVariables >::type NumEqVector
A vector with the same size as numbers of equations This is the default implementation and has to be ...
Definition numeqvector.hh:46
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:161
Definition adapt.hh:29
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:154
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition propertysystem.hh:150
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition extrusion.hh:177
Definition common/pdesolver.hh:36
ElementVolumeVariables & curElemVolVars()
Definition fvlocalassemblerbase.hh:265
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition fvlocalassemblerbase.hh:68
ElementBoundaryTypes & elemBcTypes()
Definition fvlocalassemblerbase.hh:281
Implementation & asImp_()
Definition fvlocalassemblerbase.hh:309
ElementVolumeVariables & prevElemVolVars()
Definition fvlocalassemblerbase.hh:269
ElementResidualVector evalLocalResidual() const
Definition fvlocalassemblerbase.hh:120
FVLocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol)
Definition fvlocalassemblerbase.hh:73
FVElementGeometry & fvGeometry()
Definition fvlocalassemblerbase.hh:261
const Assembler & assembler() const
Definition fvlocalassemblerbase.hh:245
ElementFluxVariablesCache & elemFluxVarsCache()
Definition fvlocalassemblerbase.hh:273
bool elementIsGhost() const
Definition fvlocalassemblerbase.hh:253
LocalResidual & localResidual()
Definition fvlocalassemblerbase.hh:277
const Element & element() const
Definition fvlocalassemblerbase.hh:249
VolumeVariables & getVolVarAccess(GridVolumeVariables &gridVolVars, ElementVolumeVariables &elemVolVars, const SubControlVolume &scv)
Definition fvlocalassemblerbase.hh:316
const SolutionVector & curSol() const
Definition fvlocalassemblerbase.hh:257
A helper class for local assemblers using numeric differentiation to determine the epsilon.
Definition numericepsilon.hh:41
static void partialDerivative(const Function &function, Scalar x0, FunctionEvalType &derivative, const FunctionEvalType &fx0, const int numericDifferenceMethod=1)
Computes the derivative of a function with repect to a function parameter.
Definition numericdifferentiation.hh:61
The interface of the coupling manager for multi domain problems.
Definition multidomain/couplingmanager.hh:60
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition subdomainboxlocalassembler.hh:268
void bindLocalViews()
Prepares all local views necessary for local assembly.
Definition subdomainboxlocalassembler.hh:312
static constexpr auto domainId
Definition subdomainboxlocalassembler.hh:91
ElementResidualVector evalLocalSourceResidual(const Element &element, const ElementVolumeVariables &elemVolVars) const
Evaluates the local source term for an element and given element volume variables.
Definition subdomainboxlocalassembler.hh:242
CouplingManager & couplingManager()
Definition subdomainboxlocalassembler.hh:348
ElementResidualVector evalLocalSourceResidual(const Element &neighbor) const
Evaluates the local source term depending on time discretization scheme.
Definition subdomainboxlocalassembler.hh:263
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Incorporate Dirichlet boundary conditions.
Definition subdomainboxlocalassembler.hh:281
void assembleResidual(SubSolutionVector &res)
Assemble the residual vector entries only.
Definition subdomainboxlocalassembler.hh:219
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacRow &jacRow, const ElementResidualVector &res, GridVariables &gridVariables)
Assemble the entries in a coupling block of the jacobian. There is no coupling block between a domain...
Definition subdomainboxlocalassembler.hh:201
const Problem & problem() const
return reference to the underlying problem
Definition subdomainboxlocalassembler.hh:344
void assembleJacobianAndResidual(JacobianMatrixRow &jacRow, SubSolutionVector &res, GridVariablesTuple &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition subdomainboxlocalassembler.hh:117
SubDomainBoxLocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol, CouplingManager &couplingManager)
Definition subdomainboxlocalassembler.hh:96
The box scheme multidomain local assembler.
Definition subdomainboxlocalassembler.hh:367
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition subdomainboxlocalassembler.hh:410
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const ElementResidualVector &res, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition subdomainboxlocalassembler.hh:496
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition subdomainboxlocalassembler.hh:650
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const ElementResidualVector &res, GridVariables &gridVariables)
Computes the coupling derivatives with respect to the given element and adds them to the global matri...
Definition subdomainboxlocalassembler.hh:734
Declares all properties used in Dumux.