3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
fclocalassembler.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 *****************************************************************************/
25#ifndef DUMUX_FC_LOCAL_ASSEMBLER_HH
26#define DUMUX_FC_LOCAL_ASSEMBLER_HH
27
28#include <dune/grid/common/gridenums.hh>
29
39
40namespace Dumux {
41
42namespace Detail {
43
45{
46 template<class... Args>
47 constexpr void operator()(Args&&...) const {}
48};
49
50template<class T, class Default>
51using NonVoidOrDefault_t = std::conditional_t<!std::is_same_v<T, void>, T, Default>;
52
53} // end namespace Detail
54
64template<class TypeTag, class Assembler, class Implementation, bool implicit>
65class FaceCenteredLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
66{
73
74 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
75
76public:
77
78 using ParentType::ParentType;
79
81 {
83 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
84 }
85
90 template <class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::NoOpFunctor>
91 void assembleJacobianAndResidual(JacobianMatrix& jac, SolutionVector& res, GridVariables& gridVariables,
92 const PartialReassembler* partialReassembler,
93 const CouplingFunction& maybeAssembleCouplingBlocks = CouplingFunction{})
94 {
95 static_assert(!std::decay_t<decltype(this->asImp_().problem())>::enableInternalDirichletConstraints(),
96 "Internal Dirichlet constraints are currently not implemented for face-centered staggered models!");
97
98 this->asImp_().bindLocalViews();
99 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
100 const auto eIdxGlobal = gridGeometry.elementMapper().index(this->element());
101 if (partialReassembler
102 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
103 {
104 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
105 for (const auto& scv : scvs(this->fvGeometry()))
106 res[scv.dofIndex()] += residual[scv.localDofIndex()];
107
108 // assemble the coupling blocks for coupled models (does nothing if not coupled)
109 maybeAssembleCouplingBlocks(residual);
110 }
111 else if (!this->elementIsGhost())
112 {
113 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
114
115 if (this->element().partitionType() == Dune::InteriorEntity)
116 {
117 for (const auto& scv : scvs(this->fvGeometry()))
118 res[scv.dofIndex()] += residual[scv.localDofIndex()];
119 }
120 else
121 {
122 // handle residual and matrix entries for parallel runs
123 for (const auto& scv : scvs(this->fvGeometry()))
124 {
125 const auto& facet = this->element().template subEntity <1> (scv.indexInElement());
126 // make sure that the residual at border entities is consistent by adding the
127 // the contribution from the neighboring overlap element's scv
128 if (facet.partitionType() == Dune::BorderEntity)
129 res[scv.dofIndex()] += residual[scv.localDofIndex()];
130
131 // set the matrix entries of all DOFs withing the overlap region (except the border DOF)
132 // to 1.0 and the residual entries to 0.0
133 else
134 {
135 const auto idx = scv.dofIndex();
136 jac[idx][idx] = 0.0;
137 for (int i = 0; i < jac[idx][idx].size(); ++i)
138 jac[idx][idx][i][i] = 1.0;
139 res[idx] = 0;
140 }
141 }
142 }
143
144 // assemble the coupling blocks for coupled models (does nothing if not coupled)
145 maybeAssembleCouplingBlocks(residual);
146 }
147 else
148 DUNE_THROW(Dune::NotImplemented, "Ghost elements not supported");
149
150
151 auto applyDirichlet = [&] (const auto& scvI,
152 const auto& dirichletValues,
153 const auto eqIdx,
154 const auto pvIdx)
155 {
156 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
157
158 auto& row = jac[scvI.dofIndex()];
159 for (auto col = row.begin(); col != row.end(); ++col)
160 row[col.index()][eqIdx] = 0.0;
161
162 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
163
164 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof TODO periodic
165 // if (this->assembler().gridGeometry().dofOnPeriodicBoundary(scvI.dofIndex()))
166 // {
167 // const auto periodicDof = this->assembler().gridGeometry().periodicallyMappedDof(scvI.dofIndex());
168 // res[periodicDof][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
169 // const auto end = jac[periodicDof].end();
170 // for (auto it = jac[periodicDof].begin(); it != end; ++it)
171 // (*it) = periodicDof != it.index() ? 0.0 : 1.0;
172 // }
173 };
174
175 this->asImp_().enforceDirichletConstraints(applyDirichlet);
176 }
177
182 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
183 {
184 this->asImp_().bindLocalViews();
185 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
186
187 auto applyDirichlet = [&] (const auto& scvI,
188 const auto& dirichletValues,
189 const auto eqIdx,
190 const auto pvIdx)
191 {
192 auto& row = jac[scvI.dofIndex()];
193 for (auto col = row.begin(); col != row.end(); ++col)
194 row[col.index()][eqIdx] = 0.0;
195
196 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
197 };
198
199 this->asImp_().enforceDirichletConstraints(applyDirichlet);
200 }
201
205 void assembleResidual(SolutionVector& res)
206 {
207 this->asImp_().bindLocalViews();
208 const auto residual = this->evalLocalResidual();
209
210 for (const auto& scv : scvs(this->fvGeometry()))
211 res[scv.dofIndex()] += residual[scv.localDofIndex()];
212
213 auto applyDirichlet = [&] (const auto& scvI,
214 const auto& dirichletValues,
215 const auto eqIdx,
216 const auto pvIdx)
217 {
218 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[eqIdx] - dirichletValues[pvIdx];
219 };
220
221 this->asImp_().enforceDirichletConstraints(applyDirichlet);
222 }
223
227 template<typename ApplyFunction>
228 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
229 {
230 // enforce Dirichlet boundary conditions
231 this->asImp_().evalDirichletBoundaries(applyDirichlet);
232 // take care of internal Dirichlet constraints (if enabled)
233 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
234 }
235
239 template< typename ApplyDirichletFunctionType >
240 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
241 {
242 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
243 // and set the residual to (privar - dirichletvalue)
244 if (this->elemBcTypes().hasDirichlet())
245 {
246 for (const auto& scvf : scvfs(this->fvGeometry()))
247 {
248 if (scvf.isFrontal() && scvf.boundary())
249 {
250 const auto bcTypes = this->elemBcTypes()[scvf.localIndex()];
251 if (bcTypes.hasDirichlet())
252 {
253 const auto& scv = this->fvGeometry().scv(scvf.insideScvIdx());
254 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvf);
255
256 // set the Dirichlet conditions in residual and jacobian
257 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
258 {
259 for (int pvIdx = 0; pvIdx < GridView::dimension; ++pvIdx)
260 {
261 if (bcTypes.isDirichlet(pvIdx) && pvIdx == scv.dofAxis()) // TODO?
262 applyDirichlet(scv, dirichletValues, eqIdx, pvIdx);
263 }
264 }
265 }
266 }
267 }
268 }
269 }
270
275 template<class... Args>
276 void maybeUpdateCouplingContext(Args&&...) {}
277
282 template<class... Args>
284};
285
294template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
296
302template<class TypeTag, class Assembler, class Implementation>
303class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
304: public FaceCenteredLocalAssemblerBase<TypeTag, Assembler,
305 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>, true>
306{
310 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
312 using FVElementGeometry = typename GridGeometry::LocalView;
313 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
314 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
318
319 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
320 static constexpr bool enableGridFluxVarsCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
321
322public:
323
325 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
327
334 template <class PartialReassembler = DefaultPartialReassembler>
335 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
336 const PartialReassembler* partialReassembler = nullptr)
337 {
338 // get some aliases for convenience
339 const auto& problem = this->asImp_().problem();
340 const auto& element = this->element();
341 const auto& fvGeometry = this->fvGeometry();
342 const auto& curSol = this->asImp_().curSol();
343
344 auto&& curElemVolVars = this->curElemVolVars();
345
346 // get the vector of the actual element residuals
347 const auto origResiduals = this->evalLocalResidual();
348
350 // //
351 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
352 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
353 // actual element. In the actual element we evaluate the derivative of the entire residual. //
354 // //
356
357 // one residual per element facet
358 const auto numElementResiduals = element.subEntities(1);
359
360 // create the vector storing the partial derivatives
361 ElementResidualVector partialDerivs(numElementResiduals);
362
363 const auto evalSource = [&](ElementResidualVector& residual, const SubControlVolume& scv)
364 {
365 this->localResidual().evalSource(residual, problem, element, fvGeometry, curElemVolVars, scv);
366 };
367
368 const auto evalStorage = [&](ElementResidualVector& residual, const SubControlVolume& scv)
369 {
370 this->localResidual().evalStorage(residual, problem, element, fvGeometry, this->prevElemVolVars(), curElemVolVars, scv);
371 };
372
373 const auto evalFlux = [&](ElementResidualVector& residual, const SubControlVolumeFace& scvf)
374 {
375 if (!scvf.processorBoundary())
376 this->localResidual().evalFlux(residual, problem, element, fvGeometry, curElemVolVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
377 };
378
379 const auto evalDerivative = [&] (const auto& scvI, const auto& scvJ)
380 {
381 // derivative w.r.t. own DOF
382 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
383 {
384 partialDerivs = 0.0;
385 const auto& otherElement = fvGeometry.gridGeometry().element(scvJ.elementIndex());
386 auto otherElemSol = elementSolution(otherElement, curSol, fvGeometry.gridGeometry()); // TODO allow selective creation of elemsol (for one scv)
387 auto& curOtherVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
388 const VolumeVariables origOtherVolVars(curOtherVolVars);
389
390 auto evalResiduals = [&](Scalar priVar)
391 {
392 // update the volume variables and compute element residual
393 otherElemSol[scvJ.localDofIndex()][pvIdx] = priVar;
394 curOtherVolVars.update(otherElemSol, problem, otherElement, scvJ);
395 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
396
397 ElementResidualVector residual(numElementResiduals);
398 residual = 0;
399
400 evalSource(residual, scvI);
401
402 if (!this->assembler().isStationaryProblem())
403 evalStorage(residual, scvI);
404
405 for (const auto& scvf : scvfs(fvGeometry, scvI))
406 evalFlux(residual, scvf);
407
408 return residual;
409 };
410
411 // derive the residuals numerically
412 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
413 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
414 NumericDifferentiation::partialDerivative(evalResiduals, otherElemSol[scvJ.localDofIndex()][pvIdx], partialDerivs, origResiduals,
415 eps_(otherElemSol[scvJ.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
416
417 const auto updateJacobian = [&]()
418 {
419 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
420 {
421 // A[i][col][eqIdx][pvIdx] is the rate of change of
422 // the residual of equation 'eqIdx' at dof 'i'
423 // depending on the primary variable 'pvIdx' at dof
424 // 'col'.
425 A[scvI.dofIndex()][scvJ.dofIndex()][eqIdx][pvIdx] += partialDerivs[scvI.localDofIndex()][eqIdx];
426 }
427 };
428
429 using GeometryHelper = typename std::decay_t<decltype(fvGeometry.gridGeometry())>::GeometryHelper;
430 using LocalIntersectionMapper = typename std::decay_t<decltype(fvGeometry.gridGeometry())>::LocalIntersectionMapper;
431 LocalIntersectionMapper localIsMapper;
432
433 const bool isParallel = fvGeometry.gridGeometry().gridView().comm().size() > 1;
434 if (isParallel)
435 localIsMapper.update(fvGeometry.gridGeometry().gridView(), element);
436
437 if (element.partitionType() == Dune::InteriorEntity)
438 updateJacobian();
439 else
440 {
441 const auto localIdxI = scvI.indexInElement();
442 const auto localIdxJ = scvJ.indexInElement();
443
444 const auto& facetI = GeometryHelper::facet(localIsMapper.refToRealIdx(localIdxI), element);
445 // add contribution of opposite scv lying within the overlap/ghost zone
446 if (facetI.partitionType() == Dune::BorderEntity &&
447 (localIdxJ == GeometryHelper::localOppositeIdx(localIdxI) || scvJ.dofIndex() == scvI.dofIndex()))
448 updateJacobian();
449 }
450
451 if (isParallel && element.partitionType() == Dune::InteriorEntity)
452 {
453 const auto localIdxI = scvI.indexInElement();
454 const auto& facetI = GeometryHelper::facet(localIsMapper.refToRealIdx(localIdxI), element);
455 if (facetI.partitionType() == Dune::BorderEntity)
456 {
457 for (const auto& scvf : scvfs(fvGeometry, scvI))
458 {
459 if (scvf.isFrontal() || scvf.boundary())
460 continue;
461
462 // parallel scvs TODO drawing
463 if (scvf.outsideScvIdx() == scvJ.index())
464 updateJacobian();
465 else
466 {
467 // normal scvs
468 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
469 if (orthogonalScvf.boundary())
470 continue;
471
472 if (orthogonalScvf.insideScvIdx() == scvJ.index() || orthogonalScvf.outsideScvIdx() == scvJ.index())
473 updateJacobian();
474 }
475 }
476 }
477 }
478
479 // restore the original state of the scv's volume variables
480 curOtherVolVars = origOtherVolVars;
481
482 // restore the original element solution
483 otherElemSol[scvJ.localDofIndex()][pvIdx] = curSol[scvJ.dofIndex()][pvIdx];
484 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
485 // TODO additional dof dependencies
486 }
487 };
488
489 // calculation of the derivatives
490 for (const auto& scvI : scvs(fvGeometry))
491 {
492 // derivative w.r.t. own DOFs
493 evalDerivative(scvI, scvI);
494
495 // derivative w.r.t. other DOFs
496 const auto& otherScvIndices = fvGeometry.gridGeometry().connectivityMap()[scvI.index()];
497 for (const auto globalJ : otherScvIndices)
498 evalDerivative(scvI, fvGeometry.scv(globalJ));
499 }
500
501 // evaluate additional derivatives that might arise from the coupling
502 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
503
504 return origResiduals;
505 }
506};
507
508
514template<class TypeTag, class Assembler>
515class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>
516: public FaceCenteredLocalAssemblerBase<TypeTag, Assembler,
517 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false>, false>
518{
522 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
526 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
528
530
531public:
533
540 template <class PartialReassembler = DefaultPartialReassembler>
541 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
542 const PartialReassembler* partialReassembler = nullptr)
543 {
544 if (partialReassembler)
545 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
546
547 // get some aliases for convenience
548 const auto& element = this->element();
549 const auto& fvGeometry = this->fvGeometry();
550 const auto& curSol = this->curSol();
551 auto&& curElemVolVars = this->curElemVolVars();
552
553 // get the vecor of the acutal element residuals
554 const auto origResiduals = this->evalLocalResidual();
555 const auto origStorageResiduals = this->evalLocalStorageResidual();
556
558 // //
559 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
560 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
561 // actual element. In the actual element we evaluate the derivative of the entire residual. //
562 // //
564
565 // create the element solution
566 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
567
568 // create the vector storing the partial derivatives
569 ElementResidualVector partialDerivs(element.subEntities(1));
570
571 // calculation of the derivatives
572 for (auto&& scv : scvs(fvGeometry))
573 {
574 // dof index and corresponding actual pri vars
575 const auto dofIdx = scv.dofIndex();
576 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
577 const VolumeVariables origVolVars(curVolVars);
578
579 // calculate derivatives w.r.t to the privars at the dof at hand
580 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
581 {
582 partialDerivs = 0.0;
583
584 auto evalStorage = [&](Scalar priVar)
585 {
586 // auto partialDerivsTmp = partialDerivs;
587 elemSol[scv.localDofIndex()][pvIdx] = priVar;
588 curVolVars.update(elemSol, this->problem(), element, scv);
589 return this->evalLocalStorageResidual();
590 };
591
592 // derive the residuals numerically
593 static const NumericEpsilon<Scalar, numEq> eps_{this->problem().paramGroup()};
594 static const int numDiffMethod = getParamFromGroup<int>(this->problem().paramGroup(), "Assembly.NumericDifferenceMethod");
595 NumericDifferentiation::partialDerivative(evalStorage, elemSol[scv.localDofIndex()][pvIdx], partialDerivs, origStorageResiduals,
596 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
597
598 // update the global stiffness matrix with the current partial derivatives
599 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
600 {
601 // A[i][col][eqIdx][pvIdx] is the rate of change of
602 // the residual of equation 'eqIdx' at dof 'i'
603 // depending on the primary variable 'pvIdx' at dof
604 // 'col'.
605 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
606 }
607
608 // restore the original state of the scv's volume variables
609 curVolVars = origVolVars;
610
611 // restore the original element solution
612 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
613 // TODO additional dof dependencies
614 }
615 }
616 return origResiduals;
617 }
618};
619
625template<class TypeTag, class Assembler>
626class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true>
627: public FaceCenteredLocalAssemblerBase<TypeTag, Assembler,
628 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true>, true>
629{
635 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
637
639
640public:
642
649 template <class PartialReassembler = DefaultPartialReassembler>
650 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
651 const PartialReassembler* partialReassembler = nullptr)
652 {
653 if (partialReassembler)
654 DUNE_THROW(Dune::NotImplemented, "partial reassembly for analytic differentiation");
655
656 // get some aliases for convenience
657 const auto& element = this->element();
658 const auto& fvGeometry = this->fvGeometry();
659 const auto& problem = this->problem();
660 const auto& curElemVolVars = this->curElemVolVars();
661 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
662
663 // get the vecor of the acutal element residuals
664 const auto origResiduals = this->evalLocalResidual();
665
667 // //
668 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
669 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
670 // actual element. In the actual element we evaluate the derivative of the entire residual. //
671 // //
673
674 // calculation of the source and storage derivatives
675 for (const auto& scv : scvs(fvGeometry))
676 {
677 // dof index and corresponding actual pri vars
678 const auto dofIdx = scv.dofIndex();
679 const auto& volVars = curElemVolVars[scv];
680
681 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
682 // only if the problem is instationary we add derivative of storage term
683 // TODO if e.g. porosity depends on all dofs in the element, we would have off-diagonal matrix entries!?
684 if (!this->assembler().isStationaryProblem())
685 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
686 problem,
687 element,
688 fvGeometry,
689 volVars,
690 scv);
691
692 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
693 // add source term derivatives
694 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
695 problem,
696 element,
697 fvGeometry,
698 volVars,
699 scv);
700 }
701
702 // localJacobian[scvIdx][otherScvIdx][eqIdx][priVarIdx] of the fluxes
703 for (const auto& scvf : scvfs(fvGeometry))
704 {
705 if (!scvf.boundary())
706 {
707 // add flux term derivatives
708 this->localResidual().addFluxDerivatives(A,
709 problem,
710 element,
711 fvGeometry,
712 curElemVolVars,
713 elemFluxVarsCache,
714 scvf);
715 }
716
717 // the boundary gets special treatment to simplify
718 // for the user
719 else
720 {
721 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
722 if (this->elemBcTypes()[insideScv.localDofIndex()].hasNeumann())
723 {
724 // add flux term derivatives
725 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
726 problem,
727 element,
728 fvGeometry,
729 curElemVolVars,
730 elemFluxVarsCache,
731 scvf);
732 }
733 }
734 }
735
736 return origResiduals;
737 }
738};
739
745template<class TypeTag, class Assembler>
746class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false>
747: public FaceCenteredLocalAssemblerBase<TypeTag, Assembler,
748 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false>, false>
749{
755 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
757
759
760public:
762
769 template <class PartialReassembler = DefaultPartialReassembler>
770 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
771 const PartialReassembler* partialReassembler = nullptr)
772 {
773 if (partialReassembler)
774 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
775
776 // get some aliases for convenience
777 const auto& element = this->element();
778 const auto& fvGeometry = this->fvGeometry();
779 const auto& problem = this->problem();
780 const auto& curElemVolVars = this->curElemVolVars();
781
782 // get the vector of the actual element residuals
783 const auto origResiduals = this->evalLocalResidual();
784
786 // //
787 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
788 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
789 // actual element. In the actual element we evaluate the derivative of the entire residual. //
790 // //
792
793 // calculation of the source and storage derivatives
794 for (const auto& scv : scvs(fvGeometry))
795 {
796 // dof index and corresponding actual pri vars
797 const auto dofIdx = scv.dofIndex();
798 const auto& volVars = curElemVolVars[scv];
799
800 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
801 // only if the problem is instationary we add derivative of storage term
802 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
803 problem,
804 element,
805 fvGeometry,
806 volVars,
807 scv);
808 }
809
810 return origResiduals;
811 }
812};
813
814} // end namespace Dumux
815
816#endif
An enum class to define various differentiation methods available in order to compute the derivatives...
An enum class to define the colors of elements and vertices required for partial Jacobian reassembly.
An adapter class for local assemblers using numeric differentiation.
Detects which entries in the Jacobian have to be recomputed.
A class for numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
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
@ green
does not need to be reassembled
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
std::conditional_t<!std::is_same_v< T, void >, T, Default > NonVoidOrDefault_t
Definition: fclocalassembler.hh:51
Definition: fclocalassembler.hh:45
constexpr void operator()(Args &&...) const
Definition: fclocalassembler.hh:47
A base class for all local cell-centered assemblers.
Definition: fclocalassembler.hh:66
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition: fclocalassembler.hh:228
void assembleResidual(SolutionVector &res)
Assemble the residual only.
Definition: fclocalassembler.hh:205
void assembleJacobian(JacobianMatrix &jac, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: fclocalassembler.hh:182
void assembleJacobianAndResidual(JacobianMatrix &jac, SolutionVector &res, GridVariables &gridVariables, const PartialReassembler *partialReassembler, const CouplingFunction &maybeAssembleCouplingBlocks=CouplingFunction{})
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition: fclocalassembler.hh:91
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition: fclocalassembler.hh:276
void bindLocalViews()
Definition: fclocalassembler.hh:80
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition: fclocalassembler.hh:240
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition: fclocalassembler.hh:283
An assembler for Jacobian and residual contribution per element (Face-centered methods)
Definition: fclocalassembler.hh:295
Face-centered scheme local assembler using numeric differentiation and implicit time discretization.
Definition: fclocalassembler.hh:306
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: fclocalassembler.hh:325
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix &A, GridVariables &gridVariables, const PartialReassembler *partialReassembler=nullptr)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: fclocalassembler.hh:335
GetPropType< TypeTag, Properties::LocalResidual > LocalResidual
Definition: fclocalassembler.hh:324
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix &A, GridVariables &gridVariables, const PartialReassembler *partialReassembler=nullptr)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: fclocalassembler.hh:541
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix &A, GridVariables &gridVariables, const PartialReassembler *partialReassembler=nullptr)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: fclocalassembler.hh:650
ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix &A, GridVariables &gridVariables, const PartialReassembler *partialReassembler=nullptr)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: fclocalassembler.hh:770
A base class for all local assemblers.
Definition: fvlocalassemblerbase.hh:48
void bindLocalViews()
Convenience function bind and prepare all relevant variables required for the evaluation of the local...
Definition: fvlocalassemblerbase.hh:185
ElementVolumeVariables & curElemVolVars()
The current element volume variables.
Definition: fvlocalassemblerbase.hh:265
ElementBoundaryTypes & elemBcTypes()
The element's boundary types.
Definition: fvlocalassemblerbase.hh:281
Implementation & asImp_()
Definition: fvlocalassemblerbase.hh:309
ElementResidualVector evalLocalResidual() const
Convenience function to evaluate the complete local residual for the current element....
Definition: fvlocalassemblerbase.hh:120
const Problem & problem() const
The problem.
Definition: fvlocalassemblerbase.hh:241
FVElementGeometry & fvGeometry()
The global finite volume geometry.
Definition: fvlocalassemblerbase.hh:261
bool elementIsGhost() const
Returns if element is a ghost entity.
Definition: fvlocalassemblerbase.hh:253
const Element & element() const
The current element.
Definition: fvlocalassemblerbase.hh:249
A helper class for local assemblers using numeric differentiation to determine the epsilon.
Definition: numericepsilon.hh:41
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:432
EntityColor elementColor(size_t idx) const
Definition: partialreassembler.hh:503
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
Declares all properties used in Dumux.