version 3.11-dev
Loading...
Searching...
No Matches
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// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_FC_LOCAL_ASSEMBLER_HH
14#define DUMUX_FC_LOCAL_ASSEMBLER_HH
15
16#include <optional>
17
18#include <dune/grid/common/gridenums.hh>
19
29
30namespace Dumux {
31
32namespace Detail {
33
35{
36 template<class... Args>
37 constexpr void operator()(Args&&...) const {}
38};
39
40template<class T, class Default>
41using NonVoidOrDefault_t = std::conditional_t<!std::is_same_v<T, void>, T, Default>;
42
43} // end namespace Detail
44
54template<class TypeTag, class Assembler, class Implementation, bool implicit>
55class FaceCenteredLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
56{
65
66 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
67
68public:
69
70 using ParentType::ParentType;
71
73 {
75 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
76 }
77
82 template <class ResidualVector, class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::NoOpFunctor>
83 void assembleJacobianAndResidual(JacobianMatrix& jac, ResidualVector& res, GridVariables& gridVariables,
84 const PartialReassembler* partialReassembler,
85 const CouplingFunction& maybeAssembleCouplingBlocks = CouplingFunction{})
86 {
87 this->asImp_().bindLocalViews();
88 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
89 const auto eIdxGlobal = gridGeometry.elementMapper().index(this->element());
90 if (partialReassembler
91 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
92 {
93 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
94 for (const auto& scv : scvs(this->fvGeometry()))
95 res[scv.dofIndex()] += residual[scv.localDofIndex()];
96
97 // assemble the coupling blocks for coupled models (does nothing if not coupled)
98 maybeAssembleCouplingBlocks(residual);
99 }
100 else if (!this->elementIsGhost())
101 {
102 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
103
104 if (this->element().partitionType() == Dune::InteriorEntity)
105 {
106 for (const auto& scv : scvs(this->fvGeometry()))
107 res[scv.dofIndex()] += residual[scv.localDofIndex()];
108 }
109 else
110 {
111 // handle residual and matrix entries for parallel runs
112 for (const auto& scv : scvs(this->fvGeometry()))
113 {
114 const auto& facet = this->element().template subEntity <1> (scv.indexInElement());
115 // make sure that the residual at border entities is consistent by adding the
116 // the contribution from the neighboring overlap element's scv
117 if (facet.partitionType() == Dune::BorderEntity)
118 res[scv.dofIndex()] += residual[scv.localDofIndex()];
119
120 // set the matrix entries of all DOFs within the overlap region (except the border DOF)
121 // to 1.0 and the residual entries to 0.0
122 else
123 {
124 const auto idx = scv.dofIndex();
125 jac[idx][idx] = 0.0;
126 for (int i = 0; i < jac[idx][idx].size(); ++i)
127 jac[idx][idx][i][i] = 1.0;
128 res[idx] = 0;
129 }
130 }
131 }
132
133 // assemble the coupling blocks for coupled models (does nothing if not coupled)
134 maybeAssembleCouplingBlocks(residual);
135 }
136 else
137 DUNE_THROW(Dune::NotImplemented, "Ghost elements not supported");
138
139
140 auto applyDirichlet = [&] (const auto& scvI,
141 const auto& dirichletValues,
142 const auto eqIdx,
143 const auto pvIdx)
144 {
145 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
146
147 auto& row = jac[scvI.dofIndex()];
148 for (auto col = row.begin(); col != row.end(); ++col)
149 row[col.index()][eqIdx] = 0.0;
150
151 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
152 };
153
154 this->asImp_().enforceDirichletConstraints(applyDirichlet);
155 }
156
161 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
162 {
163 this->asImp_().bindLocalViews();
164 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
165
166 auto applyDirichlet = [&] (const auto& scvI,
167 const auto& dirichletValues,
168 const auto eqIdx,
169 const auto pvIdx)
170 {
171 auto& row = jac[scvI.dofIndex()];
172 for (auto col = row.begin(); col != row.end(); ++col)
173 row[col.index()][eqIdx] = 0.0;
174
175 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
176 };
177
178 this->asImp_().enforceDirichletConstraints(applyDirichlet);
179 }
180
184 template<class ResidualVector>
185 void assembleResidual(ResidualVector& res)
186 {
187 this->asImp_().bindLocalViews();
188 const auto residual = this->evalLocalResidual();
189
190 for (const auto& scv : scvs(this->fvGeometry()))
191 res[scv.dofIndex()] += residual[scv.localDofIndex()];
192
193 auto applyDirichlet = [&] (const auto& scvI,
194 const auto& dirichletValues,
195 const auto eqIdx,
196 const auto pvIdx)
197 {
198 res[scvI.dofIndex()][eqIdx] = this->curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
199 };
200
201 this->asImp_().enforceDirichletConstraints(applyDirichlet);
202 }
203
207 template<typename ApplyFunction>
208 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
209 {
210 // enforce Dirichlet boundary conditions
211 this->asImp_().evalDirichletBoundaries(applyDirichlet);
212 // take care of internal Dirichlet constraints (if enabled)
213 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
214 }
215
219 template< typename ApplyDirichletFunctionType >
220 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
221 {
222 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
223 // and set the residual to (privar - dirichletvalue)
224 if (this->elemBcTypes().hasDirichlet())
225 {
226 for (const auto& scvf : scvfs(this->fvGeometry()))
227 {
228 if (scvf.isFrontal() && scvf.boundary())
229 {
230 const auto bcTypes = this->elemBcTypes()[scvf.localIndex()];
231 if (bcTypes.hasDirichlet())
232 {
233 const auto& scv = this->fvGeometry().scv(scvf.insideScvIdx());
234 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvf);
235
236 // set the Dirichlet conditions in residual and jacobian
237 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
238 {
239 static_assert(numEq == 1, "Not yet implemented for more than one vector-valued primary variable");
240 const int pvIdx = eqIdx;
241 const int componentIdx = scv.dofAxis();
242 if (bcTypes.isDirichlet(componentIdx))
243 applyDirichlet(scv, std::array<Scalar,1>{{dirichletValues[componentIdx]}}, eqIdx, pvIdx);
244 }
245 }
246 }
247 }
248 }
249 }
250
254 template<typename ApplyFunction, class P = Problem, typename std::enable_if_t<P::enableInternalDirichletConstraints(), int> = 0>
255 void enforceInternalDirichletConstraints(const ApplyFunction& applyDirichlet)
256 {
257 // enforce Dirichlet constraints strongly by overwriting partial derivatives with 1 or 0
258 // and set the residual to (privar - dirichletvalue)
259 for (const auto& scvI : scvs(this->fvGeometry()))
260 {
261 if (const auto dirichletValue = this->asImp_().internalDirichletValue(scvI))
262 {
263 // set the Dirichlet conditions in residual and jacobian
264 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
265 {
266 static_assert(numEq == 1, "Not yet implemented for more than one vector-valued primary variable");
267 const int pvIdx = eqIdx;
268 applyDirichlet(scvI, std::array<Scalar,1>{{*dirichletValue}}, eqIdx, pvIdx);
269 }
270 }
271 }
272 }
273
274 template<typename ApplyFunction, class P = Problem, typename std::enable_if_t<!P::enableInternalDirichletConstraints(), int> = 0>
275 void enforceInternalDirichletConstraints(const ApplyFunction& applyDirichlet)
276 {}
277
283 template<class P = Problem, typename std::enable_if_t<P::enableInternalDirichletConstraints(), int> = 0>
284 std::optional<Scalar> internalDirichletValue(const SubControlVolume& scv) const
285 {
286 const auto& problem = this->asImp_().problem();
287 const auto axis = scv.dofAxis();
288 if (problem.hasInternalDirichletConstraint(this->element(), scv)[axis])
289 return problem.internalDirichlet(this->element(), scv)[axis];
290
291 const auto& gridGeometry = problem.gridGeometry();
292 if (gridGeometry.dofOnPeriodicBoundary(scv.dofIndex()))
293 {
294 const auto& periodicScv = this->fvGeometry().outsidePeriodicScv(scv);
295 const auto periodicElement = gridGeometry.element(periodicScv.elementIndex());
296 if (problem.hasInternalDirichletConstraint(periodicElement, periodicScv)[axis])
297 return problem.internalDirichlet(periodicElement, periodicScv)[axis];
298 }
299
300 return {};
301 }
302
307 template<class... Args>
308 void maybeUpdateCouplingContext(Args&&...) {}
309
314 template<class... Args>
316};
317
327template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
329
335template<class TypeTag, class Assembler, class Implementation>
336class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
338 TypeTag, Assembler,
339 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
340 /*implicit=*/true
341>
342{
346 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
348 using FVElementGeometry = typename GridGeometry::LocalView;
349 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
350 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
354
355 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
357
358public:
359
361 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
362 using ParentType::ParentType;
363
370 template <class PartialReassembler = DefaultPartialReassembler>
371 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
372 const PartialReassembler* partialReassembler = nullptr)
373 {
374 // get some aliases for convenience
375 const auto& problem = this->asImp_().problem();
376 const auto& element = this->element();
377 const auto& fvGeometry = this->fvGeometry();
378 const auto& curSol = this->asImp_().curSol();
379 auto&& curElemVolVars = this->curElemVolVars();
380
381 // get the vector of the actual element residuals
382 const auto origResiduals = this->evalLocalResidual();
383
385 // //
386 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
387 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
388 // actual element. In the actual element we evaluate the derivative of the entire residual. //
389 // //
391
392 // one residual per element facet
393 const auto numElementResiduals = fvGeometry.numScv();
394
395 // create the vector storing the partial derivatives
396 ElementResidualVector partialDerivs(numElementResiduals);
397
398 const auto evalSource = [&](ElementResidualVector& residual, const SubControlVolume& scv)
399 {
400 this->localResidual().evalSource(residual, problem, element, fvGeometry, curElemVolVars, scv);
401 };
402
403 const auto evalStorage = [&](ElementResidualVector& residual, const SubControlVolume& scv)
404 {
405 this->localResidual().evalStorage(residual, problem, element, fvGeometry, this->prevElemVolVars(), curElemVolVars, scv);
406 };
407
408 const auto evalFlux = [&](ElementResidualVector& residual, const SubControlVolumeFace& scvf)
409 {
410 if (!scvf.processorBoundary())
411 this->localResidual().evalFlux(residual, problem, element, fvGeometry, curElemVolVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
412 };
413
414 const auto evalDerivative = [&] (const auto& scvI, const auto& scvJ)
415 {
416 // derivative w.r.t. own DOF
417 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
418 {
419 partialDerivs = 0.0;
420 const auto& otherElement = fvGeometry.gridGeometry().element(scvJ.elementIndex());
421 auto otherElemSol = elementSolution(otherElement, curSol, fvGeometry.gridGeometry()); // TODO allow selective creation of elemsol (for one scv)
422 auto& curOtherVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
423 const VolumeVariables origOtherVolVars(curOtherVolVars);
424
425 auto evalResiduals = [&](PrimaryVariable priVar)
426 {
427 // update the volume variables and compute element residual
428 otherElemSol[scvJ.localDofIndex()][pvIdx] = priVar;
429 curOtherVolVars.update(otherElemSol, problem, otherElement, scvJ);
430 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
431
432 ElementResidualVector residual(numElementResiduals);
433 residual = 0;
434
435 evalSource(residual, scvI);
436
437 if (!this->assembler().isStationaryProblem())
438 evalStorage(residual, scvI);
439
440 for (const auto& scvf : scvfs(fvGeometry, scvI))
441 evalFlux(residual, scvf);
442
443 return residual;
444 };
445
446 // derive the residuals numerically
447 static const NumericEpsilon<PrimaryVariable, numEq> eps_{this->asImp_().problem().paramGroup()};
448 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
449 NumericDifferentiation::partialDerivative(evalResiduals, otherElemSol[scvJ.localDofIndex()][pvIdx], partialDerivs, origResiduals,
450 eps_(otherElemSol[scvJ.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
451
452 const auto updateJacobian = [&]()
453 {
454 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
455 {
456 // A[i][col][eqIdx][pvIdx] is the rate of change of
457 // the residual of equation 'eqIdx' at dof 'i'
458 // depending on the primary variable 'pvIdx' at dof
459 // 'col'.
460 A[scvI.dofIndex()][scvJ.dofIndex()][eqIdx][pvIdx] += partialDerivs[scvI.localDofIndex()][eqIdx];
461 }
462 };
463
464 if (element.partitionType() == Dune::InteriorEntity)
465 updateJacobian();
466 else
467 {
468 const auto localIdxI = scvI.indexInElement();
469 const auto& facetI = element.template subEntity <1> (localIdxI);
470
471 if (facetI.partitionType() == Dune::BorderEntity)
472 updateJacobian();
473 }
474
475 // restore the original state of the scv's volume variables
476 curOtherVolVars = origOtherVolVars;
477
478 // restore the original element solution
479 otherElemSol[scvJ.localDofIndex()][pvIdx] = curSol[scvJ.dofIndex()][pvIdx];
480 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
481 // TODO additional dof dependencies
482 }
483 };
484
485 // calculation of the derivatives
486 for (const auto& scvI : scvs(fvGeometry))
487 {
488 // derivative w.r.t. own DOFs
489 evalDerivative(scvI, scvI);
490
491 // derivative w.r.t. other DOFs
492 const auto& otherScvIndices = fvGeometry.gridGeometry().connectivityMap()[scvI.index()];
493 for (const auto globalJ : otherScvIndices)
494 evalDerivative(scvI, fvGeometry.scv(globalJ));
495 }
496
497 // evaluate additional derivatives that might arise from the coupling
498 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
499
500 return origResiduals;
501 }
502};
503
504
510template<class TypeTag, class Assembler, class Implementation>
511class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false, Implementation>
513 TypeTag, Assembler,
514 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
515 /*implicit=*/false
516>
517{
521 using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
525
527
528public:
530 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
531 using ParentType::ParentType;
532
539 template <class PartialReassembler = DefaultPartialReassembler>
540 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
541 const PartialReassembler* partialReassembler = nullptr)
542 {
543 if (partialReassembler)
544 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
545
546 // get some aliases for convenience
547 const auto& problem = this->asImp_().problem();
548 const auto& element = this->element();
549 const auto& fvGeometry = this->fvGeometry();
550 const auto& curSol = this->asImp_().curSol();
551 auto&& curElemVolVars = this->curElemVolVars();
552
553 // get the vector of the actual 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(fvGeometry.numScv());
570
571 // calculation of the derivatives
572 for (const 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 = [&](PrimaryVariable priVar)
585 {
586 // auto partialDerivsTmp = partialDerivs;
587 elemSol[scv.localDofIndex()][pvIdx] = priVar;
588 curVolVars.update(elemSol, problem, element, scv);
589 return this->evalLocalStorageResidual();
590 };
591
592 // derive the residuals numerically
593 static const NumericEpsilon<PrimaryVariable, numEq> eps_{problem.paramGroup()};
594 static const int numDiffMethod = getParamFromGroup<int>(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 }
614 }
615 return origResiduals;
616 }
617};
618
624template<class TypeTag, class Assembler, class Implementation>
625class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true, Implementation>
627 TypeTag, Assembler,
628 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>,
629 /*implicit=*/true
630>
631{
637
639
640public:
642 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
643 using ParentType::ParentType;
644
651 template <class PartialReassembler = DefaultPartialReassembler>
652 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
653 const PartialReassembler* partialReassembler = nullptr)
654 {
655 if (partialReassembler)
656 DUNE_THROW(Dune::NotImplemented, "partial reassembly for analytic differentiation");
657
658 // get some aliases for convenience
659 const auto& element = this->element();
660 const auto& fvGeometry = this->fvGeometry();
661 const auto& problem = this->asImp_().problem();
662 const auto& curElemVolVars = this->curElemVolVars();
663 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
664
665 // get the vecor of the actual element residuals
666 const auto origResiduals = this->evalLocalResidual();
667
669 // //
670 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
671 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
672 // actual element. In the actual element we evaluate the derivative of the entire residual. //
673 // //
675
676 // calculation of the source and storage derivatives
677 for (const auto& scv : scvs(fvGeometry))
678 {
679 // dof index and corresponding actual pri vars
680 const auto dofIdx = scv.dofIndex();
681 const auto& volVars = curElemVolVars[scv];
682
683 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
684 // only if the problem is instationary we add derivative of storage term
685 // TODO if e.g. porosity depends on all dofs in the element, we would have off-diagonal matrix entries!?
686 if (!this->assembler().isStationaryProblem())
687 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
688 problem,
689 element,
691 volVars,
692 scv);
693
694 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
695 // add source term derivatives
696 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
697 problem,
698 element,
700 volVars,
701 scv);
702 }
703
704 // localJacobian[scvIdx][otherScvIdx][eqIdx][priVarIdx] of the fluxes
705 for (const auto& scvf : scvfs(fvGeometry))
706 {
707 if (!scvf.boundary())
708 {
709 // add flux term derivatives
710 this->localResidual().addFluxDerivatives(A,
711 problem,
712 element,
716 scvf);
717 }
718
719 // the boundary gets special treatment to simplify
720 // for the user
721 else
722 {
723 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
724 if (this->elemBcTypes()[insideScv.localDofIndex()].hasNeumann())
725 {
726 // add flux term derivatives
727 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
728 problem,
729 element,
733 scvf);
734 }
735 }
736 }
737
738 return origResiduals;
739 }
740};
741
747template<class TypeTag, class Assembler, class Implementation>
748class FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false, Implementation>
750 TypeTag, Assembler,
751 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>,
752 /*implicit=*/false
753>
754{
760
762
763public:
765 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
766 using ParentType::ParentType;
767
774 template <class PartialReassembler = DefaultPartialReassembler>
775 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
776 const PartialReassembler* partialReassembler = nullptr)
777 {
778 if (partialReassembler)
779 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
780
781 // get some aliases for convenience
782 const auto& element = this->element();
783 const auto& fvGeometry = this->fvGeometry();
784 const auto& problem = this->asImp_().problem();
785 const auto& curElemVolVars = this->curElemVolVars();
786
787 // get the vector of the actual element residuals
788 const auto origResiduals = this->evalLocalResidual();
789
791 // //
792 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
793 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
794 // actual element. In the actual element we evaluate the derivative of the entire residual. //
795 // //
797
798 // calculation of the source and storage derivatives
799 for (const auto& scv : scvs(fvGeometry))
800 {
801 // dof index and corresponding actual pri vars
802 const auto dofIdx = scv.dofIndex();
803 const auto& volVars = curElemVolVars[scv];
804
805 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
806 // only if the problem is instationary we add derivative of storage term
807 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
808 problem,
809 element,
811 volVars,
812 scv);
813 }
814
815 return origResiduals;
816 }
817};
818
819} // end namespace Dumux
820
821#endif
A base class for all local assemblers.
void bindLocalViews()
Definition assembly/fvlocalassemblerbase.hh:173
ElementVolumeVariables & curElemVolVars()
Definition assembly/fvlocalassemblerbase.hh:253
ElementBoundaryTypes & elemBcTypes()
Definition assembly/fvlocalassemblerbase.hh:269
Implementation & asImp_()
Definition assembly/fvlocalassemblerbase.hh:297
ElementResidualVector evalLocalResidual() const
Definition assembly/fvlocalassemblerbase.hh:108
const Problem & problem() const
Definition assembly/fvlocalassemblerbase.hh:229
FVLocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol)
Definition assembly/fvlocalassemblerbase.hh:61
FVElementGeometry & fvGeometry()
Definition assembly/fvlocalassemblerbase.hh:249
bool elementIsGhost() const
Definition assembly/fvlocalassemblerbase.hh:241
std::decay_t< decltype(std::declval< Assembler >().localResidual())> LocalResidual
Definition assembly/fvlocalassemblerbase.hh:55
const Element & element() const
Definition assembly/fvlocalassemblerbase.hh:237
VolumeVariables & getVolVarAccess(GridVolumeVariables &gridVolVars, ElementVolumeVariables &elemVolVars, const SubControlVolume &scv)
Definition assembly/fvlocalassemblerbase.hh:304
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition fclocalassembler.hh:361
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:371
typename ParentType::LocalResidual LocalResidual
Definition fclocalassembler.hh:360
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition fclocalassembler.hh:642
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:652
typename ParentType::LocalResidual LocalResidual
Definition fclocalassembler.hh:641
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition fclocalassembler.hh:530
typename ParentType::LocalResidual LocalResidual
Definition fclocalassembler.hh:529
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:540
typename ParentType::LocalResidual LocalResidual
Definition fclocalassembler.hh:764
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition fclocalassembler.hh:765
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:775
A base class for all local cell-centered assemblers.
Definition fclocalassembler.hh:56
void enforceInternalDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforces Dirichlet constraints if enabled in the problem.
Definition fclocalassembler.hh:255
void assembleJacobianAndResidual(JacobianMatrix &jac, ResidualVector &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:83
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition fclocalassembler.hh:208
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:161
std::optional< Scalar > internalDirichletValue(const SubControlVolume &scv) const
The value of the internal Dirichlet constraint on the velocity component of a sub-control volume,...
Definition fclocalassembler.hh:284
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition fclocalassembler.hh:308
void bindLocalViews()
Definition fclocalassembler.hh:72
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition fclocalassembler.hh:220
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition fclocalassembler.hh:315
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition fclocalassembler.hh:185
An assembler for Jacobian and residual contribution per element (Face-centered methods).
Definition fclocalassembler.hh:328
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:56
A helper class for local assemblers using numeric differentiation to determine the epsilon.
Definition numericepsilon.hh:33
detects which entries in the Jacobian have to be recomputed
Definition partialreassembler.hh:418
EntityColor elementColor(size_t idx) const
Definition partialreassembler.hh:489
Defines all properties used in Dumux.
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.
The global face variables class for staggered models.
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition diffmethod.hh:25
@ analytic
Definition diffmethod.hh:26
@ numeric
Definition diffmethod.hh:26
@ green
does not need to be reassembled
Definition entitycolor.hh:40
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::cctpfa||GridGeometry::discMethod==DiscretizationMethods::ccmpfa, CCElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for cell-centered schemes.
Definition cellcentered/elementsolution.hh:101
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:165
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition propertysystem.hh:296
Definition cvfelocalresidual.hh:25
std::conditional_t<!std::is_same_v< T, void >, T, Default > NonVoidOrDefault_t
Definition fclocalassembler.hh:41
Definition adapt.hh:17
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition localdof.hh:82
A class for numeric differentiation.
An adapter class for local assemblers using numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Detects which entries in the Jacobian have to be recomputed.
Definition fclocalassembler.hh:35
constexpr void operator()(Args &&...) const
Definition fclocalassembler.hh:37