version 3.11-dev
Loading...
Searching...
No Matches
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
28#include <dumux/common/typetraits/localdofs_.hh>
29#include <dumux/common/typetraits/boundary_.hh>
30
36
39
40#include "cvfevolvarsdeflectionpolicy_.hh"
41
43
44namespace Dumux {
45
46#ifndef DOXYGEN
47namespace Detail::CVFE {
48
49struct NoOperator
50{
51 template<class... Args>
52 constexpr void operator()(Args&&...) const {}
53};
54
55template<class X, class Y>
56using Impl = std::conditional_t<!std::is_same_v<X, void>, X, Y>;
57
58} // end namespace Detail
59#endif // DOXYGEN
60
70template<class TypeTag, class Assembler, class Implementation, bool implicit>
71class CVFELocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
72{
77 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
78 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
80 using SolutionVector = typename Assembler::SolutionVector;
82 using FVElementGeometry = typename GridGeometry::LocalView;
83
84 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
85 static constexpr int dim = GridGeometry::GridView::dimension;
86
87public:
88
89 using ParentType::ParentType;
90
92 {
94 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
95 }
96
97
102 template <class ResidualVector, class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::CVFE::NoOperator>
103 void assembleJacobianAndResidual(JacobianMatrix& jac, ResidualVector& res, GridVariables& gridVariables,
104 const PartialReassembler* partialReassembler = nullptr,
105 const CouplingFunction& maybeAssembleCouplingBlocks = {})
106 {
107 this->asImp_().bindLocalViews();
108 const auto eIdxGlobal = this->asImp_().problem().gridGeometry().elementMapper().index(this->element());
109 if (partialReassembler
110 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
111 {
112 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
113
114 for (const auto& localDof : localDofs(this->fvGeometry()))
115 res[localDof.dofIndex()] += residual[localDof.index()];
116
117 // assemble the coupling blocks for coupled models (does nothing if not coupled)
118 maybeAssembleCouplingBlocks(residual);
119 }
120 else if (!this->elementIsGhost())
121 {
122 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
123
124 for (const auto& localDof : localDofs(this->fvGeometry()))
125 res[localDof.dofIndex()] += residual[localDof.index()];
126
127 // assemble the coupling blocks for coupled models (does nothing if not coupled)
128 maybeAssembleCouplingBlocks(residual);
129 }
130 else
131 {
132 // Treatment of ghost elements
133 assert(this->elementIsGhost());
134
135 // handle dofs per codimension
136 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
137 Dune::Hybrid::forEach(std::make_integer_sequence<int, dim+1>{}, [&](auto d)
138 {
139 constexpr int codim = dim - d;
140 const auto& localCoeffs = gridGeometry.feCache().get(this->element().type()).localCoefficients();
141 for (int idx = 0; idx < localCoeffs.size(); ++idx)
142 {
143 const auto& localKey = localCoeffs.localKey(idx);
144
145 // skip if we are not handling this codim right now
146 if (localKey.codim() != codim)
147 continue;
148
149 // do not change the non-ghost entities
150 auto entity = this->element().template subEntity<codim>(localKey.subEntity());
151 if (entity.partitionType() == Dune::InteriorEntity || entity.partitionType() == Dune::BorderEntity)
152 continue;
153
154 // Set identity rows for ALL DOFs of this ghost entity.
155 // Entities with multiple DOFs (e.g. PQ3 edge interior DOFs with 2 per edge)
156 // require iterating over all DOF indices via asMultiMapper(dofMapper()).indices(entity).
157 using BlockType = typename JacobianMatrix::block_type;
158 for (const auto dofIndex : asMultiMapper(gridGeometry.dofMapper()).indices(entity))
159 {
160 BlockType &J = jac[dofIndex][dofIndex];
161 for (int j = 0; j < BlockType::rows; ++j)
162 J[j][j] = 1.0;
163 res[dofIndex] = 0;
164 }
165 }
166 });
167 }
168
169 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
170 const auto& dirichletValues,
171 const auto eqIdx,
172 const auto pvIdx)
173 {
174 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
175
176 auto& row = jac[scvOrLocalDofI.dofIndex()];
177 for (auto col = row.begin(); col != row.end(); ++col)
178 row[col.index()][eqIdx] = 0.0;
179
180 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
181
182 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
183 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
184 {
185 for (const auto periodicDof :
186 Dumux::Deprecated::rangeOfPeriodicallyMappedDofs(this->asImp_().problem().gridGeometry(), scvOrLocalDofI.dofIndex()))
187 {
188 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
189
190 auto& rowP = jac[periodicDof];
191 for (auto col = rowP.begin(); col != rowP.end(); ++col)
192 rowP[col.index()][eqIdx] = 0.0;
193
194 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
195 }
196 }
197 };
198
199 this->asImp_().enforceDirichletConstraints(applyDirichlet);
200 }
201
206 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
207 {
208 this->asImp_().bindLocalViews();
209 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
210
211 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
212 const auto& dirichletValues,
213 const auto eqIdx,
214 const auto pvIdx)
215 {
216 auto& row = jac[scvOrLocalDofI.dofIndex()];
217 for (auto col = row.begin(); col != row.end(); ++col)
218 row[col.index()][eqIdx] = 0.0;
219
220 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
221
222 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
223 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
224 {
225 for (const auto periodicDof :
226 Dumux::Deprecated::rangeOfPeriodicallyMappedDofs(this->asImp_().problem().gridGeometry(), scvOrLocalDofI.dofIndex()))
227 {
228 auto& rowP = jac[periodicDof];
229 for (auto col = rowP.begin(); col != rowP.end(); ++col)
230 rowP[col.index()][eqIdx] = 0.0;
231
232 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
233 }
234 }
235 };
236
237 this->asImp_().enforceDirichletConstraints(applyDirichlet);
238 }
239
243 template <class ResidualVector>
244 void assembleResidual(ResidualVector& res)
245 {
246 this->asImp_().bindLocalViews();
247 const auto residual = this->evalLocalResidual();
248
249 for (const auto& localDof : localDofs(this->fvGeometry()))
250 res[localDof.dofIndex()] += residual[localDof.index()];
251
252 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
253 const auto& dirichletValues,
254 const auto eqIdx,
255 const auto pvIdx)
256 {
257 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
258
259 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
260 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
261 {
262 for (const auto periodicDof :
263 Dumux::Deprecated::rangeOfPeriodicallyMappedDofs(this->asImp_().problem().gridGeometry(), scvOrLocalDofI.dofIndex()))
264 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
265 }
266 };
267
268 this->asImp_().enforceDirichletConstraints(applyDirichlet);
269 }
270
272 template<typename ApplyFunction>
273 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
274 {
275 // enforce Dirichlet boundary conditions
276 this->asImp_().evalDirichletBoundaries(applyDirichlet);
277 // take care of internal Dirichlet constraints (if enabled)
278 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
279 }
280
284 template< typename ApplyDirichletFunctionType >
285 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
286 {
287 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
288 // and set the residual to (privar - dirichletvalue)
289 // when having the new boundary interface Dirichlet conditions are incorporated via constraints
290 if constexpr (!Detail::hasProblemBoundaryTypesForFaceFunction<Problem, FVElementGeometry>())
291 {
292 if (this->elemBcTypes().hasDirichlet())
293 {
294 for (const auto& scvI : scvs(this->fvGeometry()))
295 {
296 const auto bcTypes = this->elemBcTypes().get(this->fvGeometry(), scvI);
297 if (bcTypes.hasDirichlet())
298 {
299 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvI);
300
301 // set the Dirichlet conditions in residual and jacobian
302 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
303 {
304 if (bcTypes.isDirichlet(eqIdx))
305 {
306 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
307 assert(0 <= pvIdx && pvIdx < numEq);
308 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
309 }
310 }
311 }
312 }
313 }
314 }
315 }
316
321 template<class... Args>
322 void maybeUpdateCouplingContext(Args&&...) {}
323
328 template<class... Args>
330
331};
332
342template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
344
350template<class TypeTag, class Assembler, class Implementation>
351class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
352: public CVFELocalAssemblerBase<TypeTag, Assembler,
353 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
354 true>
355{
361 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
364
365 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
367
368 static constexpr bool enableGridFluxVarsCache
369 = GridVariables::GridFluxVariablesCache::cachingEnabled;
370 static constexpr bool solutionDependentFluxVarsCache
371 = GridVariables::GridFluxVariablesCache::FluxVariablesCache::isSolDependent;
372
373public:
374
376 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
377 using ParentType::ParentType;
378
385 template <class PartialReassembler = DefaultPartialReassembler>
386 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
387 const PartialReassembler* partialReassembler = nullptr)
388 {
389 // get some aliases for convenience
390 const auto& element = this->element();
391 const auto& fvGeometry = this->fvGeometry();
392 const auto& curSol = this->asImp_().curSol();
393
394 auto&& curElemVolVars = this->curElemVolVars();
395 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
396
397 // get the vector of the actual element residuals
398 const auto origResiduals = this->evalLocalResidual();
399
401 // //
402 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
403 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
404 // actual element. In the actual element we evaluate the derivative of the entire residual. //
405 // //
407
408 // if all volvars in the stencil have to be updated or if it's enough to only update the
409 // volVars for the scv whose associated dof has been deflected
410 static const bool updateAllVolVars = getParamFromGroup<bool>(
411 this->asImp_().problem().paramGroup(), "Assembly.BoxVolVarsDependOnAllElementDofs", false
412 );
413
414 // create the element solution
417
418 // create the vector storing the partial derivatives
419 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
420
421 auto deflectionPolicy = Detail::CVFE::makeVariablesDeflectionPolicy(
422 gridVariables.curGridVolVars(),
425 updateAllVolVars
426 );
427
428 auto assembleDerivative = [&, this](const auto& localDof)
429 {
430 // dof index and corresponding actual pri vars
431 const auto dofIdx = localDof.dofIndex();
432 const auto localIdx = localDof.index();
433 deflectionPolicy.store(localDof);
434
435 // calculate derivatives w.r.t to the privars at the dof at hand
436 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
437 {
438 partialDerivs = 0.0;
439
440 auto evalResiduals = [&](PrimaryVariable priVar)
441 {
442 // update the volume variables and compute element residual
443 elemSol[localIdx][pvIdx] = priVar;
444 deflectionPolicy.update(elemSol, localDof, this->asImp_().problem());
445 if constexpr (solutionDependentFluxVarsCache)
446 {
448 if constexpr (enableGridFluxVarsCache)
449 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
450 }
451 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
452 return this->evalLocalResidual();
453 };
454
455 // derive the residuals numerically
456 static const NumericEpsilon<PrimaryVariable, numEq> eps_{this->asImp_().problem().paramGroup()};
457 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
458 NumericDifferentiation::partialDerivative(evalResiduals, elemSol[localIdx][pvIdx], partialDerivs, origResiduals,
459 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
460
461 // update the global stiffness matrix with the current partial derivatives
462 for (const auto& localDofJ : localDofs(fvGeometry))
463 {
464 // don't add derivatives for green dofs
465 if (!partialReassembler
466 || partialReassembler->dofColor(localDofJ.dofIndex()) != EntityColor::green)
467 {
468 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
469 {
470 // A[i][col][eqIdx][pvIdx] is the rate of change of
471 // the residual of equation 'eqIdx' at dof 'i'
472 // depending on the primary variable 'pvIdx' at dof
473 // 'col'.
474 A[localDofJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[localDofJ.index()][eqIdx];
475 }
476 }
477 }
478
479 // restore the original state of the scv's volume variables
480 deflectionPolicy.restore(localDof);
481
482 // restore the original element solution
483 elemSol[localIdx][pvIdx] = curSol[localDof.dofIndex()][pvIdx];
484 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
485 }
486 };
487
488 // calculation of the derivatives
489 for (const auto& localDof : localDofs(fvGeometry))
490 assembleDerivative(localDof);
491
492 // restore original state of the flux vars cache in case of global caching.
493 // In the case of local caching this is obsolete because the elemFluxVarsCache used here goes out of scope after this.
494 if constexpr (enableGridFluxVarsCache)
495 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
496
497 // evaluate additional derivatives that might arise from the coupling (no-op if not coupled)
498 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
499
500 return origResiduals;
501 }
502
503}; // implicit CVFEAssembler with numeric Jacobian
504
510template<class TypeTag, class Assembler, class Implementation>
511class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false, Implementation>
512: public CVFELocalAssemblerBase<TypeTag, Assembler,
513 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
514 false>
515{
522
523 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
525
526public:
527
529 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
530 using ParentType::ParentType;
531
538 template <class PartialReassembler = DefaultPartialReassembler>
539 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
540 const PartialReassembler* partialReassembler = nullptr)
541 {
542 if (partialReassembler)
543 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
544
545 // get some aliases for convenience
546 const auto& element = this->element();
547 const auto& fvGeometry = this->fvGeometry();
548 const auto& curSol = this->asImp_().curSol();
549 auto&& curElemVolVars = this->curElemVolVars();
550
551 // get the vecor of the actual element residuals
552 const auto origResiduals = this->evalLocalResidual();
553 const auto origStorageResiduals = this->evalLocalStorageResidual();
554
556 // //
557 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
558 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
559 // actual element. In the actual element we evaluate the derivative of the entire residual. //
560 // //
562
563 // create the element solution
566
567 // create the vector storing the partial derivatives
568 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
569
570 // calculation of the derivatives
571 for (const auto& scv : scvs(fvGeometry))
572 {
573 // dof index and corresponding actual pri vars
574 const auto localIdx = scv.localDofIndex();
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[localIdx][pvIdx] = priVar;
588 curVolVars.update(elemSol, this->asImp_().problem(), element, scv);
589 return this->evalLocalStorageResidual();
590 };
591
592 // derive the residuals numerically
593 static const NumericEpsilon<PrimaryVariable, numEq> eps_{this->asImp_().problem().paramGroup()};
594 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
595 NumericDifferentiation::partialDerivative(evalStorage, elemSol[localIdx][pvIdx], partialDerivs, origStorageResiduals,
596 eps_(elemSol[localIdx][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[localIdx][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[localIdx][pvIdx] = curSol[dofIdx][pvIdx];
613 // TODO additional dof dependencies
614 }
615 }
616
617 return origResiduals;
618 }
619}; // explicit CVFEAssembler with numeric Jacobian
620
626template<class TypeTag, class Assembler, class Implementation>
627class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true, Implementation>
628: public CVFELocalAssemblerBase<TypeTag, Assembler,
629 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>>,
630 true>
631{
636
637public:
638
640 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
641 using ParentType::ParentType;
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->asImp_().problem();
660 const auto& curElemVolVars = this->curElemVolVars();
661 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
662
663 // get the vecor of the actual 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,
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,
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,
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().get(fvGeometry, insideScv).hasNeumann())
723 {
724 // add flux term derivatives
725 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
726 problem,
727 element,
731 scvf);
732 }
733 }
734 }
735
736 return origResiduals;
737 }
738
739}; // implicit CVFEAssembler with analytic Jacobian
740
746template<class TypeTag, class Assembler, class Implementation>
747class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false, Implementation>
748: public CVFELocalAssemblerBase<TypeTag, Assembler,
749 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>>,
750 false>
751{
756
757public:
758
760 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
761 using ParentType::ParentType;
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->asImp_().problem();
780 const auto& curElemVolVars = this->curElemVolVars();
781
782 // get the vecor 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,
806 volVars,
807 scv);
808 }
809
810 return origResiduals;
811 }
812
813}; // explicit CVFEAssembler with analytic Jacobian
814
815} // end namespace Dumux
816
817#endif
A base class for all local assemblers.
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:760
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:770
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:759
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:650
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:640
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:639
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:376
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:375
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:386
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.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 assembly/cvfelocalassembler.hh:539
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:528
A base class for all local CVFE assemblers.
Definition assembly/cvfelocalassembler.hh:72
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition assembly/cvfelocalassembler.hh:273
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition assembly/cvfelocalassembler.hh:244
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition assembly/cvfelocalassembler.hh:322
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:206
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition assembly/cvfelocalassembler.hh:285
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:103
void bindLocalViews()
Definition assembly/cvfelocalassembler.hh:91
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition assembly/cvfelocalassembler.hh:329
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition assembly/cvfelocalassembler.hh:343
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
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
Defines all properties used in Dumux.
The local element solution class for control-volume finite element methods.
Helpers for deprecation.
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.
Type traits for classes providing a grid discretization.
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
decltype(auto) gridDiscretization(const T &t, Args &&... args)
The grid discretization.
Definition griddiscretization.hh:65
Class representing dofs on elements for control-volume finite element schemes.
Adapter to expose a multi-DOF mapper interface for single- and multi-DOF mappers.
Definition elementinterpolationpointdatacache.hh:21
Definition adapt.hh:17
constexpr auto asMultiMapper(const Mapper &mapper)
Definition multimapperview.hh:48
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition localdof.hh:82
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.