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
42namespace Dumux {
43
44#ifndef DOXYGEN
45namespace Detail::CVFE {
46
47struct NoOperator
48{
49 template<class... Args>
50 constexpr void operator()(Args&&...) const {}
51};
52
53template<class X, class Y>
54using Impl = std::conditional_t<!std::is_same_v<X, void>, X, Y>;
55
56} // end namespace Detail
57#endif // DOXYGEN
58
68template<class TypeTag, class Assembler, class Implementation, bool implicit>
69class CVFELocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Implementation, implicit>
70{
75 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
76 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
78 using SolutionVector = typename Assembler::SolutionVector;
80 using FVElementGeometry = typename GridGeometry::LocalView;
81
82 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
83 static constexpr int dim = GridGeometry::GridView::dimension;
84
85public:
86
87 using ParentType::ParentType;
88
90 {
92 this->elemBcTypes().update(this->asImp_().problem(), this->element(), this->fvGeometry());
93 }
94
95
100 template <class ResidualVector, class PartialReassembler = DefaultPartialReassembler, class CouplingFunction = Detail::CVFE::NoOperator>
101 void assembleJacobianAndResidual(JacobianMatrix& jac, ResidualVector& res, GridVariables& gridVariables,
102 const PartialReassembler* partialReassembler = nullptr,
103 const CouplingFunction& maybeAssembleCouplingBlocks = {})
104 {
105 this->asImp_().bindLocalViews();
106 const auto eIdxGlobal = this->asImp_().problem().gridGeometry().elementMapper().index(this->element());
107 if (partialReassembler
108 && partialReassembler->elementColor(eIdxGlobal) == EntityColor::green)
109 {
110 const auto residual = this->asImp_().evalLocalResidual(); // forward to the internal implementation
111
112 for (const auto& localDof : localDofs(this->fvGeometry()))
113 res[localDof.dofIndex()] += residual[localDof.index()];
114
115 // assemble the coupling blocks for coupled models (does nothing if not coupled)
116 maybeAssembleCouplingBlocks(residual);
117 }
118 else if (!this->elementIsGhost())
119 {
120 const auto residual = this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler); // forward to the internal implementation
121
122 for (const auto& localDof : localDofs(this->fvGeometry()))
123 res[localDof.dofIndex()] += residual[localDof.index()];
124
125 // assemble the coupling blocks for coupled models (does nothing if not coupled)
126 maybeAssembleCouplingBlocks(residual);
127 }
128 else
129 {
130 // Treatment of ghost elements
131 assert(this->elementIsGhost());
132
133 // handle dofs per codimension
134 const auto& gridGeometry = this->asImp_().problem().gridGeometry();
135 Dune::Hybrid::forEach(std::make_integer_sequence<int, dim+1>{}, [&](auto d)
136 {
137 constexpr int codim = dim - d;
138 const auto& localCoeffs = gridGeometry.feCache().get(this->element().type()).localCoefficients();
139 for (int idx = 0; idx < localCoeffs.size(); ++idx)
140 {
141 const auto& localKey = localCoeffs.localKey(idx);
142
143 // skip if we are not handling this codim right now
144 if (localKey.codim() != codim)
145 continue;
146
147 // do not change the non-ghost entities
148 auto entity = this->element().template subEntity<codim>(localKey.subEntity());
149 if (entity.partitionType() == Dune::InteriorEntity || entity.partitionType() == Dune::BorderEntity)
150 continue;
151
152 // Set identity rows for ALL DOFs of this ghost entity.
153 // Entities with multiple DOFs (e.g. PQ3 edge interior DOFs with 2 per edge)
154 // require iterating over all DOF indices via asMultiMapper(dofMapper()).indices(entity).
155 using BlockType = typename JacobianMatrix::block_type;
156 for (const auto dofIndex : asMultiMapper(gridGeometry.dofMapper()).indices(entity))
157 {
158 BlockType &J = jac[dofIndex][dofIndex];
159 for (int j = 0; j < BlockType::rows; ++j)
160 J[j][j] = 1.0;
161 res[dofIndex] = 0;
162 }
163 }
164 });
165 }
166
167 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
168 const auto& dirichletValues,
169 const auto eqIdx,
170 const auto pvIdx)
171 {
172 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
173
174 auto& row = jac[scvOrLocalDofI.dofIndex()];
175 for (auto col = row.begin(); col != row.end(); ++col)
176 row[col.index()][eqIdx] = 0.0;
177
178 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
179
180 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
181 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
182 {
183 const auto periodicDof = this->asImp_().problem().gridGeometry().periodicallyMappedDof(scvOrLocalDofI.dofIndex());
184 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
185
186 auto& rowP = jac[periodicDof];
187 for (auto col = rowP.begin(); col != rowP.end(); ++col)
188 rowP[col.index()][eqIdx] = 0.0;
189
190 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
191 }
192 };
193
194 this->asImp_().enforceDirichletConstraints(applyDirichlet);
195 }
196
201 void assembleJacobian(JacobianMatrix& jac, GridVariables& gridVariables)
202 {
203 this->asImp_().bindLocalViews();
204 this->asImp_().assembleJacobianAndResidualImpl(jac, gridVariables); // forward to the internal implementation
205
206 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
207 const auto& dirichletValues,
208 const auto eqIdx,
209 const auto pvIdx)
210 {
211 auto& row = jac[scvOrLocalDofI.dofIndex()];
212 for (auto col = row.begin(); col != row.end(); ++col)
213 row[col.index()][eqIdx] = 0.0;
214
215 jac[scvOrLocalDofI.dofIndex()][scvOrLocalDofI.dofIndex()][eqIdx][pvIdx] = 1.0;
216
217 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
218 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
219 {
220 const auto periodicDof = this->asImp_().problem().gridGeometry().periodicallyMappedDof(scvOrLocalDofI.dofIndex());
221
222 auto& rowP = jac[periodicDof];
223 for (auto col = rowP.begin(); col != rowP.end(); ++col)
224 rowP[col.index()][eqIdx] = 0.0;
225
226 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
227 }
228 };
229
230 this->asImp_().enforceDirichletConstraints(applyDirichlet);
231 }
232
236 template <class ResidualVector>
237 void assembleResidual(ResidualVector& res)
238 {
239 this->asImp_().bindLocalViews();
240 const auto residual = this->evalLocalResidual();
241
242 for (const auto& localDof : localDofs(this->fvGeometry()))
243 res[localDof.dofIndex()] += residual[localDof.index()];
244
245 auto applyDirichlet = [&] (const auto& scvOrLocalDofI,
246 const auto& dirichletValues,
247 const auto eqIdx,
248 const auto pvIdx)
249 {
250 res[scvOrLocalDofI.dofIndex()][eqIdx] = this->curElemVolVars()[scvOrLocalDofI].priVars()[pvIdx] - dirichletValues[pvIdx];
251
252 // if a periodic dof has Dirichlet values also apply the same Dirichlet values to the other dof
253 if (this->asImp_().problem().gridGeometry().dofOnPeriodicBoundary(scvOrLocalDofI.dofIndex()))
254 {
255 const auto periodicDof = this->asImp_().problem().gridGeometry().periodicallyMappedDof(scvOrLocalDofI.dofIndex());
256 res[periodicDof][eqIdx] = this->asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
257 }
258 };
259
260 this->asImp_().enforceDirichletConstraints(applyDirichlet);
261 }
262
264 template<typename ApplyFunction>
265 void enforceDirichletConstraints(const ApplyFunction& applyDirichlet)
266 {
267 // enforce Dirichlet boundary conditions
268 this->asImp_().evalDirichletBoundaries(applyDirichlet);
269 // take care of internal Dirichlet constraints (if enabled)
270 this->asImp_().enforceInternalDirichletConstraints(applyDirichlet);
271 }
272
276 template< typename ApplyDirichletFunctionType >
277 void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
278 {
279 // enforce Dirichlet boundaries by overwriting partial derivatives with 1 or 0
280 // and set the residual to (privar - dirichletvalue)
281 // when having the new boundary interface Dirichlet conditions are incorporated via constraints
282 if constexpr (!Detail::hasProblemBoundaryTypesForFaceFunction<Problem, FVElementGeometry>())
283 {
284 if (this->elemBcTypes().hasDirichlet())
285 {
286 for (const auto& scvI : scvs(this->fvGeometry()))
287 {
288 const auto bcTypes = this->elemBcTypes().get(this->fvGeometry(), scvI);
289 if (bcTypes.hasDirichlet())
290 {
291 const auto dirichletValues = this->asImp_().problem().dirichlet(this->element(), scvI);
292
293 // set the Dirichlet conditions in residual and jacobian
294 for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
295 {
296 if (bcTypes.isDirichlet(eqIdx))
297 {
298 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
299 assert(0 <= pvIdx && pvIdx < numEq);
300 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
301 }
302 }
303 }
304 }
305 }
306 }
307 }
308
313 template<class... Args>
314 void maybeUpdateCouplingContext(Args&&...) {}
315
320 template<class... Args>
322
323};
324
334template<class TypeTag, class Assembler, DiffMethod diffMethod = DiffMethod::numeric, bool implicit = true, class Implementation = void>
336
342template<class TypeTag, class Assembler, class Implementation>
343class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true, Implementation>
344: public CVFELocalAssemblerBase<TypeTag, Assembler,
345 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
346 true>
347{
353 using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
356
357 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
359
360 static constexpr bool enableGridFluxVarsCache
361 = GridVariables::GridFluxVariablesCache::cachingEnabled;
362 static constexpr bool solutionDependentFluxVarsCache
363 = GridVariables::GridFluxVariablesCache::FluxVariablesCache::isSolDependent;
364
365public:
366
368 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
369 using ParentType::ParentType;
370
377 template <class PartialReassembler = DefaultPartialReassembler>
378 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
379 const PartialReassembler* partialReassembler = nullptr)
380 {
381 // get some aliases for convenience
382 const auto& element = this->element();
383 const auto& fvGeometry = this->fvGeometry();
384 const auto& curSol = this->asImp_().curSol();
385
386 auto&& curElemVolVars = this->curElemVolVars();
387 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
388
389 // get the vector of the actual element residuals
390 const auto origResiduals = this->evalLocalResidual();
391
393 // //
394 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
395 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
396 // actual element. In the actual element we evaluate the derivative of the entire residual. //
397 // //
399
400 // if all volvars in the stencil have to be updated or if it's enough to only update the
401 // volVars for the scv whose associated dof has been deflected
402 static const bool updateAllVolVars = getParamFromGroup<bool>(
403 this->asImp_().problem().paramGroup(), "Assembly.BoxVolVarsDependOnAllElementDofs", false
404 );
405
406 // create the element solution
409
410 // create the vector storing the partial derivatives
411 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
412
413 auto deflectionPolicy = Detail::CVFE::makeVariablesDeflectionPolicy(
414 gridVariables.curGridVolVars(),
417 updateAllVolVars
418 );
419
420 auto assembleDerivative = [&, this](const auto& localDof)
421 {
422 // dof index and corresponding actual pri vars
423 const auto dofIdx = localDof.dofIndex();
424 const auto localIdx = localDof.index();
425 deflectionPolicy.store(localDof);
426
427 // calculate derivatives w.r.t to the privars at the dof at hand
428 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
429 {
430 partialDerivs = 0.0;
431
432 auto evalResiduals = [&](PrimaryVariable priVar)
433 {
434 // update the volume variables and compute element residual
435 elemSol[localIdx][pvIdx] = priVar;
436 deflectionPolicy.update(elemSol, localDof, this->asImp_().problem());
437 if constexpr (solutionDependentFluxVarsCache)
438 {
440 if constexpr (enableGridFluxVarsCache)
441 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
442 }
443 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
444 return this->evalLocalResidual();
445 };
446
447 // derive the residuals numerically
448 static const NumericEpsilon<PrimaryVariable, numEq> eps_{this->asImp_().problem().paramGroup()};
449 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
450 NumericDifferentiation::partialDerivative(evalResiduals, elemSol[localIdx][pvIdx], partialDerivs, origResiduals,
451 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
452
453 // update the global stiffness matrix with the current partial derivatives
454 for (const auto& localDofJ : localDofs(fvGeometry))
455 {
456 // don't add derivatives for green dofs
457 if (!partialReassembler
458 || partialReassembler->dofColor(localDofJ.dofIndex()) != EntityColor::green)
459 {
460 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
461 {
462 // A[i][col][eqIdx][pvIdx] is the rate of change of
463 // the residual of equation 'eqIdx' at dof 'i'
464 // depending on the primary variable 'pvIdx' at dof
465 // 'col'.
466 A[localDofJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[localDofJ.index()][eqIdx];
467 }
468 }
469 }
470
471 // restore the original state of the scv's volume variables
472 deflectionPolicy.restore(localDof);
473
474 // restore the original element solution
475 elemSol[localIdx][pvIdx] = curSol[localDof.dofIndex()][pvIdx];
476 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
477 }
478 };
479
480 // calculation of the derivatives
481 for (const auto& localDof : localDofs(fvGeometry))
482 assembleDerivative(localDof);
483
484 // restore original state of the flux vars cache in case of global caching.
485 // In the case of local caching this is obsolete because the elemFluxVarsCache used here goes out of scope after this.
486 if constexpr (enableGridFluxVarsCache)
487 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
488
489 // evaluate additional derivatives that might arise from the coupling (no-op if not coupled)
490 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
491
492 return origResiduals;
493 }
494
495}; // implicit CVFEAssembler with numeric Jacobian
496
502template<class TypeTag, class Assembler, class Implementation>
503class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false, Implementation>
504: public CVFELocalAssemblerBase<TypeTag, Assembler,
505 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
506 false>
507{
514
515 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
517
518public:
519
521 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
522 using ParentType::ParentType;
523
530 template <class PartialReassembler = DefaultPartialReassembler>
531 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
532 const PartialReassembler* partialReassembler = nullptr)
533 {
534 if (partialReassembler)
535 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
536
537 // get some aliases for convenience
538 const auto& element = this->element();
539 const auto& fvGeometry = this->fvGeometry();
540 const auto& curSol = this->asImp_().curSol();
541 auto&& curElemVolVars = this->curElemVolVars();
542
543 // get the vecor of the actual element residuals
544 const auto origResiduals = this->evalLocalResidual();
545 const auto origStorageResiduals = this->evalLocalStorageResidual();
546
548 // //
549 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
550 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
551 // actual element. In the actual element we evaluate the derivative of the entire residual. //
552 // //
554
555 // create the element solution
558
559 // create the vector storing the partial derivatives
560 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
561
562 // calculation of the derivatives
563 for (const auto& scv : scvs(fvGeometry))
564 {
565 // dof index and corresponding actual pri vars
566 const auto localIdx = scv.localDofIndex();
567 const auto dofIdx = scv.dofIndex();
568 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
569 const VolumeVariables origVolVars(curVolVars);
570
571 // calculate derivatives w.r.t to the privars at the dof at hand
572 for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
573 {
574 partialDerivs = 0.0;
575
576 auto evalStorage = [&](PrimaryVariable priVar)
577 {
578 // auto partialDerivsTmp = partialDerivs;
579 elemSol[localIdx][pvIdx] = priVar;
580 curVolVars.update(elemSol, this->asImp_().problem(), element, scv);
581 return this->evalLocalStorageResidual();
582 };
583
584 // derive the residuals numerically
585 static const NumericEpsilon<PrimaryVariable, numEq> eps_{this->asImp_().problem().paramGroup()};
586 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(), "Assembly.NumericDifferenceMethod");
587 NumericDifferentiation::partialDerivative(evalStorage, elemSol[localIdx][pvIdx], partialDerivs, origStorageResiduals,
588 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
589
590 // update the global stiffness matrix with the current partial derivatives
591 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
592 {
593 // A[i][col][eqIdx][pvIdx] is the rate of change of
594 // the residual of equation 'eqIdx' at dof 'i'
595 // depending on the primary variable 'pvIdx' at dof
596 // 'col'.
597 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[localIdx][eqIdx];
598 }
599
600 // restore the original state of the scv's volume variables
601 curVolVars = origVolVars;
602
603 // restore the original element solution
604 elemSol[localIdx][pvIdx] = curSol[dofIdx][pvIdx];
605 // TODO additional dof dependencies
606 }
607 }
608
609 return origResiduals;
610 }
611}; // explicit CVFEAssembler with numeric Jacobian
612
618template<class TypeTag, class Assembler, class Implementation>
619class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/true, Implementation>
620: public CVFELocalAssemblerBase<TypeTag, Assembler,
621 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>>,
622 true>
623{
628
629public:
630
632 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
633 using ParentType::ParentType;
634
641 template <class PartialReassembler = DefaultPartialReassembler>
642 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
643 const PartialReassembler* partialReassembler = nullptr)
644 {
645 if (partialReassembler)
646 DUNE_THROW(Dune::NotImplemented, "partial reassembly for analytic differentiation");
647
648 // get some aliases for convenience
649 const auto& element = this->element();
650 const auto& fvGeometry = this->fvGeometry();
651 const auto& problem = this->asImp_().problem();
652 const auto& curElemVolVars = this->curElemVolVars();
653 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
654
655 // get the vecor of the actual element residuals
656 const auto origResiduals = this->evalLocalResidual();
657
659 // //
660 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
661 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
662 // actual element. In the actual element we evaluate the derivative of the entire residual. //
663 // //
665
666 // calculation of the source and storage derivatives
667 for (const auto& scv : scvs(fvGeometry))
668 {
669 // dof index and corresponding actual pri vars
670 const auto dofIdx = scv.dofIndex();
671 const auto& volVars = curElemVolVars[scv];
672
673 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
674 // only if the problem is instationary we add derivative of storage term
675 // TODO if e.g. porosity depends on all dofs in the element, we would have off-diagonal matrix entries!?
676 if (!this->assembler().isStationaryProblem())
677 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
678 problem,
679 element,
681 volVars,
682 scv);
683
684 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
685 // add source term derivatives
686 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
687 problem,
688 element,
690 volVars,
691 scv);
692 }
693
694 // localJacobian[scvIdx][otherScvIdx][eqIdx][priVarIdx] of the fluxes
695 for (const auto& scvf : scvfs(fvGeometry))
696 {
697 if (!scvf.boundary())
698 {
699 // add flux term derivatives
700 this->localResidual().addFluxDerivatives(A,
701 problem,
702 element,
706 scvf);
707 }
708
709 // the boundary gets special treatment to simplify
710 // for the user
711 else
712 {
713 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
714 if (this->elemBcTypes().get(fvGeometry, insideScv).hasNeumann())
715 {
716 // add flux term derivatives
717 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
718 problem,
719 element,
723 scvf);
724 }
725 }
726 }
727
728 return origResiduals;
729 }
730
731}; // implicit CVFEAssembler with analytic Jacobian
732
738template<class TypeTag, class Assembler, class Implementation>
739class CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/false, Implementation>
740: public CVFELocalAssemblerBase<TypeTag, Assembler,
741 Detail::CVFE::Impl<Implementation, CVFELocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>>,
742 false>
743{
748
749public:
750
752 using ElementResidualVector = typename LocalResidual::ElementResidualVector;
753 using ParentType::ParentType;
754
761 template <class PartialReassembler = DefaultPartialReassembler>
762 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
763 const PartialReassembler* partialReassembler = nullptr)
764 {
765 if (partialReassembler)
766 DUNE_THROW(Dune::NotImplemented, "partial reassembly for explicit time discretization");
767
768 // get some aliases for convenience
769 const auto& element = this->element();
770 const auto& fvGeometry = this->fvGeometry();
771 const auto& problem = this->asImp_().problem();
772 const auto& curElemVolVars = this->curElemVolVars();
773
774 // get the vecor of the actual element residuals
775 const auto origResiduals = this->evalLocalResidual();
776
778 // //
779 // Calculate derivatives of all dofs in stencil with respect to the dofs in the element. In the //
780 // neighboring elements we do so by computing the derivatives of the fluxes which depend on the //
781 // actual element. In the actual element we evaluate the derivative of the entire residual. //
782 // //
784
785 // calculation of the source and storage derivatives
786 for (const auto& scv : scvs(fvGeometry))
787 {
788 // dof index and corresponding actual pri vars
789 const auto dofIdx = scv.dofIndex();
790 const auto& volVars = curElemVolVars[scv];
791
792 // derivative of this scv residual w.r.t the d.o.f. of the same scv (because of mass lumping)
793 // only if the problem is instationary we add derivative of storage term
794 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
795 problem,
796 element,
798 volVars,
799 scv);
800 }
801
802 return origResiduals;
803 }
804
805}; // explicit CVFEAssembler with analytic Jacobian
806
807} // end namespace Dumux
808
809#endif
A base class for all local assemblers.
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:752
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:762
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:751
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:642
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:632
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:631
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:368
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:367
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:378
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition assembly/cvfelocalassembler.hh:521
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:531
typename ParentType::LocalResidual LocalResidual
Definition assembly/cvfelocalassembler.hh:520
A base class for all local CVFE assemblers.
Definition assembly/cvfelocalassembler.hh:70
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition assembly/cvfelocalassembler.hh:265
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition assembly/cvfelocalassembler.hh:237
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition assembly/cvfelocalassembler.hh:314
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:201
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition assembly/cvfelocalassembler.hh:277
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:101
void bindLocalViews()
Definition assembly/cvfelocalassembler.hh:89
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition assembly/cvfelocalassembler.hh:321
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition assembly/cvfelocalassembler.hh:335
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.
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 variablesadapter.hh:17
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.