version 3.11-dev
assembly/cvfelocalassembler.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_CVFE_LOCAL_ASSEMBLER_HH
14#define DUMUX_CVFE_LOCAL_ASSEMBLER_HH
15
16#include <dune/common/exceptions.hh>
17#include <dune/common/hybridutilities.hh>
18#include <dune/common/reservedvector.hh>
19#include <dune/grid/common/gridenums.hh>
20#include <dune/istl/matrixindexset.hh>
21#include <dune/istl/bvector.hh>
22
26#include <dumux/common/typetraits/localdofs_.hh>
27#include <dumux/common/typetraits/boundary_.hh>
28
34
37
38#include "cvfevolvarsdeflectionpolicy_.hh"
39
40namespace Dumux {
41
42#ifndef DOXYGEN
43namespace Detail::CVFE {
44
45struct NoOperator
46{
47 template<class... Args>
48 constexpr void operator()(Args&&...) const {}
49};
50
51template<class X, class Y>
52using Impl = std::conditional_t<!std::is_same_v<X, void>, X, Y>;
53
54} // end namespace Detail
55#endif // DOXYGEN
56
66template<class TypeTag, class Assembler, class Implementation, bool implicit>
67class CVFELocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
68{
73 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
74 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
76 using SolutionVector = typename Assembler::SolutionVector;
78 using FVElementGeometry = typename GridGeometry::LocalView;
79
80 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
81 static constexpr int dim = GridGeometry::GridView::dimension;
82
83public:
84
85 using ParentType::ParentType;
86
88 {
90 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
91 }
92
93
98 template <class ResidualVector, class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::CVFE::NoOperator>
99 void assembleJacobianAndResidual(JacobianMatrix& jac, ResidualVector& res, GridVariables& gridVariables,
100 const PartialReassembler* partialReassembler = nullptr,
101 const CouplingFunction& maybeAssembleCouplingBlocks = {})
102 {
103 this->asImp_().bindLocalViews();
104 const auto eIdxGlobal = this->asImp_().problem().gridGeometry().elementMapper().index(this->element());
105 if (partialReassembler
106 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
107 {
108 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
109
110 for (const auto& localDof : localDofs(this->fvGeometry()))
111 res[localDof.dofIndex()] += residual[localDof.index()];
112
113 // assemble the coupling blocks for coupled models (does nothing if not coupled)
114 maybeAssembleCouplingBlocks(residual);
115 }
116 else if (!this->elementIsGhost())
117 {
118 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
119
120 for (const auto& localDof : localDofs(this->fvGeometry()))
121 res[localDof.dofIndex()] += residual[localDof.index()];
122
123 // assemble the coupling blocks for coupled models (does nothing if not coupled)
124 maybeAssembleCouplingBlocks(residual);
125 }
126 else
127 {
128 // Treatment of ghost elements
129 assert(this->elementIsGhost());
130
131 // handle dofs per codimension
132 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
133 Dune::Hybrid::forEach(std::make_integer_sequence<int, dim>{}, [&](auto d)
134 {
135 constexpr int codim = dim - d;
136 const auto& localCoeffs = gridGeometry.feCache().get(this->element().type()).localCoefficients();
137 for (int idx = 0; idx < localCoeffs.size(); ++idx)
138 {
139 const auto& localKey = localCoeffs.localKey(idx);
140
141 // skip if we are not handling this codim right now
142 if (localKey.codim() != codim)
143 continue;
144
145 // do not change the non-ghost entities
146 auto entity = this->element().template subEntity<codim>(localKey.subEntity());
147 if (entity.partitionType() == Dune::InteriorEntity || entity.partitionType() == Dune::BorderEntity)
148 continue;
149
150 // WARNING: this only works if the mapping from codim+subEntity to
151 // global dofIndex is unique (on dof per entity of this codim).
152 // For more general mappings, we should use a proper local-global mapping here.
153 // For example through dune-functions.
154 const auto dofIndex = gridGeometry.dofMapper().index(entity);
155
156 // this might be a vector-valued dof
157 using BlockType = typename JacobianMatrix::block_type;
158 BlockType &J = jac[dofIndex][dofIndex];
159 for (int j = 0; j < BlockType::rows; ++j)
160 J[j][j] = 1.0;
161
162 // set residual for the ghost dof
163 res[dofIndex] = 0;
164 }
165 });
166 }
167
168 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
169 const auto& dirichletValues,
170 const auto eqIdx,
171 const auto pvIdx)
172 {
173 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
174
175 auto& row = jac[scvOrLocalDofI.dofIndex()];
176 for (auto col = row.begin(); col != row.end(); ++col)
177 row[col.index()][eqIdx] = 0.0;
178
179 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
180
181 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
182 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
183 {
184 const auto periodicDof = this->asImp_().problem().gridGeometry().periodicallyMappedDof(scvOrLocalDofI.dofIndex());
185 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
186
187 auto& rowP = jac[periodicDof];
188 for (auto col = rowP.begin(); col != rowP.end(); ++col)
189 rowP[col.index()][eqIdx] = 0.0;
190
191 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
192 }
193 };
194
195 this->asImp_().enforceDirichletConstraints(applyDirichlet);
196 }
197
202 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
203 {
204 this->asImp_().bindLocalViews();
205 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
206
207 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
208 const auto& dirichletValues,
209 const auto eqIdx,
210 const auto pvIdx)
211 {
212 auto& row = jac[scvOrLocalDofI.dofIndex()];
213 for (auto col = row.begin(); col != row.end(); ++col)
214 row[col.index()][eqIdx] = 0.0;
215
216 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
217 };
218
219 this->asImp_().enforceDirichletConstraints(applyDirichlet);
220 }
221
225 template <class ResidualVector>
226 void assembleResidual(ResidualVector& res)
227 {
228 this->asImp_().bindLocalViews();
229 const auto residual = this->evalLocalResidual();
230
231 for (const auto& localDof : localDofs(this->fvGeometry()))
232 res[localDof.dofIndex()] += residual[localDof.index()];
233
234 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
235 const auto& dirichletValues,
236 const auto eqIdx,
237 const auto pvIdx)
238 {
239 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
240 };
241
242 this->asImp_().enforceDirichletConstraints(applyDirichlet);
243 }
244
246 template<typename ApplyFunction>
247 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
248 {
249 // enforce Dirichlet boundary conditions
250 this->asImp_().evalDirichletBoundaries(applyDirichlet);
251 // take care of internal Dirichlet constraints (if enabled)
252 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
253 }
254
258 template< typename ApplyDirichletFunctionType >
259 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
260 {
261 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
262 // and set the residual to (privar - dirichletvalue)
263 // when having the new boundary interface Dirichlet conditions are incorporated via constraints
264 if constexpr (!Detail::hasProblemBoundaryTypesForIntersectionFunction<Problem, FVElementGeometry, typename GridGeometry::GridView::Intersection>())
265 {
266 if (this->elemBcTypes().hasDirichlet())
267 {
268 for (const auto& scvI : scvs(this->fvGeometry()))
269 {
270 const auto bcTypes = this->elemBcTypes().get(this->fvGeometry(), scvI);
271 if (bcTypes.hasDirichlet())
272 {
273 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvI);
274
275 // set the Dirichlet conditions in residual and jacobian
276 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
277 {
278 if (bcTypes.isDirichlet(eqIdx))
279 {
280 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
281 assert(0 <= pvIdx && pvIdx < numEq);
282 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
283 }
284 }
285 }
286 }
287 }
288 }
289 }
290
295 template<class... Args>
296 void maybeUpdateCouplingContext(Args&&...) {}
297
302 template<class... Args>
304
305};
306
316template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
318
324template<class TypeTag, class Assembler, class Implementation>
325class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
326: public CVFELocalAssemblerBase<TypeTag, Assembler,
327 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
328 true>
329{
335 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
338
339 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
341
342 static constexpr bool enableGridFluxVarsCache
343 = GridVariables::GridFluxVariablesCache::cachingEnabled;
344 static constexpr bool solutionDependentFluxVarsCache
345 = GridVariables::GridFluxVariablesCache::FluxVariablesCache::isSolDependent;
346
347public:
348
350 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
352
359 template <class PartialReassembler = DefaultPartialReassembler>
360 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
361 const PartialReassembler* partialReassembler = nullptr)
362 {
363 // get some aliases for convenience
364 const auto& element = this->element();
365 const auto& fvGeometry = this->fvGeometry();
366 const auto& curSol = this->asImp_().curSol();
367
368 auto&& curElemVolVars = this->curElemVolVars();
369 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
370
371 // get the vector of the actual element residuals
372 const auto origResiduals = this->evalLocalResidual();
373
375 // //
376 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
377 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
378 // actual element. In the actual element we evaluate the derivative of the entire residual. //
379 // //
381
382 // if all volvars in the stencil have to be updated or if it's enough to only update the
383 // volVars for the scv whose associated dof has been deflected
384 static const bool updateAllVolVars = getParamFromGroup<bool>(
385 this->asImp_().problem().paramGroup(), "Assembly.BoxVolVarsDependOnAllElementDofs", false
386 );
387
388 // create the element solution
389 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
390
391 // create the vector storing the partial derivatives
392 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
393
394 auto deflectionPolicy = Detail::CVFE::makeVariablesDeflectionPolicy(
395 gridVariables.curGridVolVars(),
396 curElemVolVars,
397 fvGeometry,
398 updateAllVolVars
399 );
400
401 auto assembleDerivative = [&, this](const auto& localDof)
402 {
403 // dof index and corresponding actual pri vars
404 const auto dofIdx = localDof.dofIndex();
405 const auto localIdx = localDof.index();
406 deflectionPolicy.store(localDof);
407
408 // calculate derivatives w.r.t to the privars at the dof at hand
409 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
410 {
411 partialDerivs = 0.0;
412
413 auto evalResiduals = [&](Scalar priVar)
414 {
415 // update the volume variables and compute element residual
416 elemSol[localIdx][pvIdx] = priVar;
417 deflectionPolicy.update(elemSol, localDof, this->asImp_().problem());
418 if constexpr (solutionDependentFluxVarsCache)
419 {
420 elemFluxVarsCache.update(element, fvGeometry, curElemVolVars);
421 if constexpr (enableGridFluxVarsCache)
422 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
423 }
424 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
425 return this->evalLocalResidual();
426 };
427
428 // derive the residuals numerically
429 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
430 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
431 NumericDifferentiation::partialDerivative(evalResiduals, elemSol[localIdx][pvIdx], partialDerivs, origResiduals,
432 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
433
434 // update the global stiffness matrix with the current partial derivatives
435 for (const auto& localDofJ : localDofs(fvGeometry))
436 {
437 // don't add derivatives for green dofs
438 if (!partialReassembler
439 || partialReassembler->dofColor(localDofJ.dofIndex()) != EntityColor::green)
440 {
441 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
442 {
443 // A[i][col][eqIdx][pvIdx] is the rate of change of
444 // the residual of equation 'eqIdx' at dof 'i'
445 // depending on the primary variable 'pvIdx' at dof
446 // 'col'.
447 A[localDofJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[localDofJ.index()][eqIdx];
448 }
449 }
450 }
451
452 // restore the original state of the scv's volume variables
453 deflectionPolicy.restore(localDof);
454
455 // restore the original element solution
456 elemSol[localIdx][pvIdx] = curSol[localDof.dofIndex()][pvIdx];
457 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
458 }
459 };
460
461 // calculation of the derivatives
462 for (const auto& localDof : localDofs(fvGeometry))
463 assembleDerivative(localDof);
464
465 // restore original state of the flux vars cache in case of global caching.
466 // In the case of local caching this is obsolete because the elemFluxVarsCache used here goes out of scope after this.
467 if constexpr (enableGridFluxVarsCache)
468 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
469
470 // evaluate additional derivatives that might arise from the coupling (no-op if not coupled)
471 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
472
473 return origResiduals;
474 }
475
476}; // implicit CVFEAssembler with numeric Jacobian
477
483template<class TypeTag, class Assembler, class Implementation>
484class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false, Implementation>
485: public CVFELocalAssemblerBase<TypeTag, Assembler,
486 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
487 false>
488{
495
496 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
498
499public:
500
502 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
504
511 template <class PartialReassembler = DefaultPartialReassembler>
512 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
513 const PartialReassembler* partialReassembler = nullptr)
514 {
515 if (partialReassembler)
516 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
517
518 // get some aliases for convenience
519 const auto& element = this->element();
520 const auto& fvGeometry = this->fvGeometry();
521 const auto& curSol = this->asImp_().curSol();
522 auto&& curElemVolVars = this->curElemVolVars();
523
524 // get the vecor of the actual element residuals
525 const auto origResiduals = this->evalLocalResidual();
526 const auto origStorageResiduals = this->evalLocalStorageResidual();
527
529 // //
530 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
531 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
532 // actual element. In the actual element we evaluate the derivative of the entire residual. //
533 // //
535
536 // create the element solution
537 auto elemSol = elementSolution(element, curSol, fvGeometry.gridGeometry());
538
539 // create the vector storing the partial derivatives
540 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
541
542 // calculation of the derivatives
543 for (const auto& scv : scvs(fvGeometry))
544 {
545 // dof index and corresponding actual pri vars
546 const auto localIdx = scv.localDofIndex();
547 const auto dofIdx = scv.dofIndex();
548 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
549 const VolumeVariables origVolVars(curVolVars);
550
551 // calculate derivatives w.r.t to the privars at the dof at hand
552 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
553 {
554 partialDerivs = 0.0;
555
556 auto evalStorage = [&](Scalar priVar)
557 {
558 // auto partialDerivsTmp = partialDerivs;
559 elemSol[localIdx][pvIdx] = priVar;
560 curVolVars.update(elemSol, this->asImp_().problem(), element, scv);
561 return this->evalLocalStorageResidual();
562 };
563
564 // derive the residuals numerically
565 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
566 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
567 NumericDifferentiation::partialDerivative(evalStorage, elemSol[localIdx][pvIdx], partialDerivs, origStorageResiduals,
568 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
569
570 // update the global stiffness matrix with the current partial derivatives
571 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
572 {
573 // A[i][col][eqIdx][pvIdx] is the rate of change of
574 // the residual of equation 'eqIdx' at dof 'i'
575 // depending on the primary variable 'pvIdx' at dof
576 // 'col'.
577 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[localIdx][eqIdx];
578 }
579
580 // restore the original state of the scv's volume variables
581 curVolVars = origVolVars;
582
583 // restore the original element solution
584 elemSol[localIdx][pvIdx] = curSol[dofIdx][pvIdx];
585 // TODO additional dof dependencies
586 }
587 }
588
589 return origResiduals;
590 }
591}; // explicit CVFEAssembler with numeric Jacobian
592
598template<class TypeTag, class Assembler, class Implementation>
599class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true, Implementation>
600: public CVFELocalAssemblerBase<TypeTag, Assembler,
601 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>>,
602 true>
603{
608
609public:
610
612 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
614
621 template <class PartialReassembler = DefaultPartialReassembler>
622 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
623 const PartialReassembler* partialReassembler = nullptr)
624 {
625 if (partialReassembler)
626 DUNE_THROW(Dune::NotImplemented, "partial reassembly for analytic differentiation");
627
628 // get some aliases for convenience
629 const auto& element = this->element();
630 const auto& fvGeometry = this->fvGeometry();
631 const auto& problem = this->asImp_().problem();
632 const auto& curElemVolVars = this->curElemVolVars();
633 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
634
635 // get the vecor of the actual element residuals
636 const auto origResiduals = this->evalLocalResidual();
637
639 // //
640 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
641 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
642 // actual element. In the actual element we evaluate the derivative of the entire residual. //
643 // //
645
646 // calculation of the source and storage derivatives
647 for (const auto& scv : scvs(fvGeometry))
648 {
649 // dof index and corresponding actual pri vars
650 const auto dofIdx = scv.dofIndex();
651 const auto& volVars = curElemVolVars[scv];
652
653 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
654 // only if the problem is instationary we add derivative of storage term
655 // TODO if e.g. porosity depends on all dofs in the element, we would have off-diagonal matrix entries!?
656 if (!this->assembler().isStationaryProblem())
657 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
658 problem,
659 element,
660 fvGeometry,
661 volVars,
662 scv);
663
664 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
665 // add source term derivatives
666 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
667 problem,
668 element,
669 fvGeometry,
670 volVars,
671 scv);
672 }
673
674 // localJacobian[scvIdx][otherScvIdx][eqIdx][priVarIdx] of the fluxes
675 for (const auto& scvf : scvfs(fvGeometry))
676 {
677 if (!scvf.boundary())
678 {
679 // add flux term derivatives
680 this->localResidual().addFluxDerivatives(A,
681 problem,
682 element,
683 fvGeometry,
684 curElemVolVars,
685 elemFluxVarsCache,
686 scvf);
687 }
688
689 // the boundary gets special treatment to simplify
690 // for the user
691 else
692 {
693 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
694 if (this->elemBcTypes().get(fvGeometry, insideScv).hasNeumann())
695 {
696 // add flux term derivatives
697 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
698 problem,
699 element,
700 fvGeometry,
701 curElemVolVars,
702 elemFluxVarsCache,
703 scvf);
704 }
705 }
706 }
707
708 return origResiduals;
709 }
710
711}; // implicit CVFEAssembler with analytic Jacobian
712
718template<class TypeTag, class Assembler, class Implementation>
719class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false, Implementation>
720: public CVFELocalAssemblerBase<TypeTag, Assembler,
721 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>>,
722 false>
723{
728
729public:
730
732 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
734
741 template <class PartialReassembler = DefaultPartialReassembler>
742 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
743 const PartialReassembler* partialReassembler = nullptr)
744 {
745 if (partialReassembler)
746 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
747
748 // get some aliases for convenience
749 const auto& element = this->element();
750 const auto& fvGeometry = this->fvGeometry();
751 const auto& problem = this->asImp_().problem();
752 const auto& curElemVolVars = this->curElemVolVars();
753
754 // get the vecor of the actual element residuals
755 const auto origResiduals = this->evalLocalResidual();
756
758 // //
759 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
760 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
761 // actual element. In the actual element we evaluate the derivative of the entire residual. //
762 // //
764
765 // calculation of the source and storage derivatives
766 for (const auto& scv : scvs(fvGeometry))
767 {
768 // dof index and corresponding actual pri vars
769 const auto dofIdx = scv.dofIndex();
770 const auto& volVars = curElemVolVars[scv];
771
772 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
773 // only if the problem is instationary we add derivative of storage term
774 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
775 problem,
776 element,
777 fvGeometry,
778 volVars,
779 scv);
780 }
781
782 return origResiduals;
783 }
784
785}; // explicit CVFEAssembler with analytic Jacobian
786
787} // end namespace Dumux
788
789#endif
Control volume finite element local assembler using analytic differentiation and explicit time discre...
Definition: assembly/cvfelocalassembler.hh:723
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: assembly/cvfelocalassembler.hh:732
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: assembly/cvfelocalassembler.hh:742
typename ParentType::LocalResidual LocalResidual
Definition: assembly/cvfelocalassembler.hh:731
Control volume finite element local assembler using analytic differentiation and implicit time discre...
Definition: assembly/cvfelocalassembler.hh:603
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: assembly/cvfelocalassembler.hh:622
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: assembly/cvfelocalassembler.hh:612
typename ParentType::LocalResidual LocalResidual
Definition: assembly/cvfelocalassembler.hh:611
Control volume finite element local assembler using numeric differentiation and implicit time discret...
Definition: assembly/cvfelocalassembler.hh:329
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: assembly/cvfelocalassembler.hh:350
typename ParentType::LocalResidual LocalResidual
Definition: assembly/cvfelocalassembler.hh:349
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: assembly/cvfelocalassembler.hh:360
Control volume finite element local assembler using numeric differentiation and explicit time discret...
Definition: assembly/cvfelocalassembler.hh:488
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: assembly/cvfelocalassembler.hh:502
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: assembly/cvfelocalassembler.hh:512
typename ParentType::LocalResidual LocalResidual
Definition: assembly/cvfelocalassembler.hh:501
A base class for all local CVFE assemblers.
Definition: assembly/cvfelocalassembler.hh:68
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition: assembly/cvfelocalassembler.hh:247
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition: assembly/cvfelocalassembler.hh:226
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition: assembly/cvfelocalassembler.hh:296
void assembleJacobian(JacobianMatrix &jac, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: assembly/cvfelocalassembler.hh:202
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition: assembly/cvfelocalassembler.hh:259
void assembleJacobianAndResidual(JacobianMatrix &jac, ResidualVector &res, GridVariables &gridVariables, const PartialReassembler *partialReassembler=nullptr, const CouplingFunction &maybeAssembleCouplingBlocks={})
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition: assembly/cvfelocalassembler.hh:99
void bindLocalViews()
Definition: assembly/cvfelocalassembler.hh:87
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition: assembly/cvfelocalassembler.hh:303
An assembler for Jacobian and residual contribution per element (CVFE methods)
Definition: assembly/cvfelocalassembler.hh:317
A base class for all local assemblers.
Definition: assembly/fvlocalassemblerbase.hh:36
void bindLocalViews()
Convenience function bind and prepare all relevant variables required for the evaluation of the local...
Definition: assembly/fvlocalassemblerbase.hh:173
ElementVolumeVariables & curElemVolVars()
The current element volume variables.
Definition: assembly/fvlocalassemblerbase.hh:253
ElementBoundaryTypes & elemBcTypes()
The element's boundary types.
Definition: assembly/fvlocalassemblerbase.hh:269
Implementation & asImp_()
Definition: assembly/fvlocalassemblerbase.hh:297
ElementResidualVector evalLocalResidual() const
Convenience function to evaluate the complete local residual for the current element....
Definition: assembly/fvlocalassemblerbase.hh:108
const Problem & problem() const
The problem.
Definition: assembly/fvlocalassemblerbase.hh:229
FVElementGeometry & fvGeometry()
The global finite volume geometry.
Definition: assembly/fvlocalassemblerbase.hh:249
bool elementIsGhost() const
Returns if element is a ghost entity.
Definition: assembly/fvlocalassemblerbase.hh:241
std::decay_t< decltype(std::declval< Assembler >().localResidual())> LocalResidual
Definition: assembly/fvlocalassemblerbase.hh:55
const Element & element() const
The current element.
Definition: assembly/fvlocalassemblerbase.hh:237
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:50
A helper class for local assemblers using numeric differentiation to determine the epsilon.
Definition: numericepsilon.hh:29
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:420
Defines all properties used in Dumux.
The local element solution class for control-volume finite element methods.
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.
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition: diffmethod.hh:25
@ green
does not need to be reassembled
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
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Class representing dofs on elements for control-volume finite element schemes.
Definition: adapt.hh:17
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition: localdof.hh:79
auto localDofs(const FVElementGeometry &fvGeometry)
range over local dofs
Definition: localdof.hh:50
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.