14#ifndef DUMUX_EXPERIMENTAL_CVFE_LOCAL_ASSEMBLER_HH
15#define DUMUX_EXPERIMENTAL_CVFE_LOCAL_ASSEMBLER_HH
17#include <dune/common/exceptions.hh>
18#include <dune/common/hybridutilities.hh>
19#include <dune/common/reservedvector.hh>
20#include <dune/grid/common/gridenums.hh>
21#include <dune/istl/matrixindexset.hh>
22#include <dune/istl/bvector.hh>
28#include <dumux/common/typetraits/localdofs_.hh>
39#include <dumux/assembly/cvfevolvarsdeflectionpolicy_.hh>
52template<
class TypeTag,
class Assembler,
class Implementation>
59 using ElementVolumeVariables =
typename GridVariables::GridVolumeVariables::LocalView;
60 using SolutionVector =
typename Assembler::SolutionVector;
67 using ParentType::ParentType;
83 template <
class Res
idualVector,
class StageParams,
class PartialReassembler = DefaultPartialReassembler,
class CouplingFunction = Noop>
85 const StageParams& stageParams, ResidualVector& temporal, ResidualVector& spatial,
86 ResidualVector& constrainedDofs,
88 const CouplingFunction& maybeAssembleCouplingBlocks =
noop)
90 this->
asImp_().bindLocalViews();
91 const auto eIdxGlobal = this->
asImp_().problem().gridGeometry().elementMapper().index(this->
element());
96 const auto sWeight = stageParams.spatialWeight(stageParams.size()-1);
97 const auto tWeight = stageParams.temporalWeight(stageParams.size()-1);
105 spatial[scv.dofIndex()] += flux[scv.localDofIndex()];
106 temporal[scv.dofIndex()] += storage[scv.localDofIndex()];
107 origResidual[scv.localDofIndex()] += flux[scv.localDofIndex()]*sWeight + storage[scv.localDofIndex()]*tWeight;
108 res[scv.dofIndex()] += origResidual[scv.localDofIndex()];
114 if (partialReassembler && partialReassembler->elementColor(eIdxGlobal) ==
EntityColor::green)
117 maybeAssembleCouplingBlocks(origResidual);
121 this->
asImp_().assembleJacobian(jac, gridVariables, origResidual, partialReassembler);
124 maybeAssembleCouplingBlocks(origResidual);
132 const auto& gridGeometry = this->
asImp_().problem().gridGeometry();
133 Dune::Hybrid::forEach(std::make_integer_sequence<int, dim>{}, [&](
auto d)
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)
139 const auto& localKey = localCoeffs.localKey(idx);
142 if (localKey.codim() != codim)
146 auto entity = this->
element().template subEntity<codim>(localKey.subEntity());
147 if (entity.partitionType() == Dune::InteriorEntity || entity.partitionType() == Dune::BorderEntity)
154 const auto dofIndex = gridGeometry.dofMapper().index(entity);
157 using BlockType =
typename JacobianMatrix::block_type;
158 BlockType &J = jac[dofIndex][dofIndex];
159 for (
int j = 0; j < BlockType::rows; ++j)
164 constrainedDofs[dofIndex] = 1;
169 auto applyDirichlet = [&] (
const auto& scvI,
170 const auto& dirichletValues,
174 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
175 constrainedDofs[scvI.dofIndex()][eqIdx] = 1;
177 auto& row = jac[scvI.dofIndex()];
178 for (
auto col = row.begin(); col != row.end(); ++col)
179 row[col.index()][eqIdx] = 0.0;
181 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
184 if (this->
asImp_().
problem().gridGeometry().dofOnPeriodicBoundary(scvI.dofIndex()))
186 const auto periodicDof = this->
asImp_().problem().gridGeometry().periodicallyMappedDof(scvI.dofIndex());
187 res[periodicDof][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
188 constrainedDofs[periodicDof][eqIdx] = 1;
189 const auto end = jac[periodicDof].end();
190 for (
auto it = jac[periodicDof].begin(); it != end; ++it)
191 (*it) = periodicDof != it.index() ? 0.0 : 1.0;
195 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
204 this->
asImp_().bindLocalViews();
205 this->
asImp_().assembleJacobian(jac, gridVariables);
207 auto applyDirichlet = [&] (
const auto& scvI,
208 const auto& dirichletValues,
212 auto& row = jac[scvI.dofIndex()];
213 for (
auto col = row.begin(); col != row.end(); ++col)
214 row[col.index()][eqIdx] = 0.0;
216 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
219 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
225 template <
class Res
idualVector>
228 this->
asImp_().bindLocalViews();
232 res[localDof.dofIndex()] += residual[localDof.index()];
234 auto applyDirichlet = [&] (
const auto& scvI,
235 const auto& dirichletValues,
239 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
242 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
248 template<
class Res
idualVector>
251 this->
asImp_().bindLocalViews();
256 spatialRes[scv.dofIndex()] += flux[scv.localDofIndex()];
257 temporalRes[scv.dofIndex()] += storage[scv.localDofIndex()];
262 template<
typename ApplyFunction>
266 this->
asImp_().evalDirichletBoundaries(applyDirichlet);
268 this->
asImp_().enforceInternalDirichletConstraints(applyDirichlet);
274 template<
typename ApplyDirichletFunctionType >
284 if (bcTypes.hasDirichlet())
286 const auto dirichletValues = this->
asImp_().problem().dirichlet(this->
element(), scvI);
289 for (
int eqIdx = 0; eqIdx < numEq; ++eqIdx)
291 if (bcTypes.isDirichlet(eqIdx))
293 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
294 assert(0 <= pvIdx && pvIdx < numEq);
295 applyDirichlet(scvI, dirichletValues, eqIdx, pvIdx);
307 template<
class... Args>
314 template<
class... Args>
327template<
class TypeTag,
class Assembler, DiffMethod diffMethod = DiffMethod::numeric,
class Implementation =
void>
336template<
class TypeTag,
class Assembler,
class Implementation>
339 NonVoidOr<CVFELocalAssembler<TypeTag, Assembler, DiffMethod::numeric, Implementation>, Implementation>>
345 using ElementVolumeVariables =
typename GridVariables::GridVolumeVariables::LocalView;
352 static constexpr bool enableGridFluxVarsCache
353 = GridVariables::GridFluxVariablesCache::cachingEnabled;
354 static constexpr bool solutionDependentFluxVarsCache
355 = GridVariables::GridFluxVariablesCache::FluxVariablesCache::isSolDependent;
363 template <
class PartialReassembler = DefaultPartialReassembler>
368 if (this->isImplicit())
369 assembleJacobianImplicit_(A, gridVariables, origResiduals, partialReassembler);
371 assembleJacobianExplicit_(A, gridVariables, origResiduals, partialReassembler);
381 template <
class PartialReassembler = DefaultPartialReassembler>
382 void assembleJacobianImplicit_(JacobianMatrix& A,
GridVariables& gridVariables,
383 const ElementResidualVector& origResiduals,
387 const auto& element = this->element();
388 const auto& fvGeometry = this->fvGeometry();
389 const auto& curSol = this->asImp_().curSol();
391 auto&& curElemVolVars = this->curElemVolVars();
392 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
404 static const bool updateAllVolVars = getParamFromGroup<bool>(
405 this->asImp_().problem().paramGroup(),
"Assembly.BoxVolVarsDependOnAllElementDofs",
false
409 auto elemSol =
elementSolution(element, curSol, fvGeometry.gridGeometry());
412 ElementResidualVector partialDerivs(Dumux::Detail::LocalDofs::numLocalDofs(fvGeometry));
414 auto deflectionPolicy = Detail::CVFE::makeVariablesDeflectionPolicy(
415 gridVariables.curGridVolVars(),
421 auto assembleDerivative = [&,
this](
const auto& localDof)
424 const auto dofIdx = localDof.dofIndex();
425 const auto localIdx = localDof.index();
426 deflectionPolicy.store(localDof);
429 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
433 auto evalResiduals = [&](Scalar priVar)
436 elemSol[localIdx][pvIdx] = priVar;
437 deflectionPolicy.update(elemSol, localDof, this->asImp_().problem());
438 if constexpr (solutionDependentFluxVarsCache)
440 elemFluxVarsCache.update(element, fvGeometry, curElemVolVars);
441 if constexpr (enableGridFluxVarsCache)
442 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
444 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
445 return this->evalLocalResidual();
449 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
450 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(),
"Assembly.NumericDifferenceMethod");
452 eps_(elemSol[localIdx][pvIdx], pvIdx), numDiffMethod);
455 for (
const auto& localDofJ :
localDofs(fvGeometry))
458 if (!partialReassembler
461 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
467 A[localDofJ.dofIndex()][dofIdx][eqIdx][pvIdx] += partialDerivs[localDofJ.index()][eqIdx];
473 deflectionPolicy.restore(localDof);
476 elemSol[localIdx][pvIdx] = curSol[localDof.dofIndex()][pvIdx];
477 this->asImp_().maybeUpdateCouplingContext(localDof, elemSol, pvIdx);
482 for (
const auto& localDof :
localDofs(fvGeometry))
483 assembleDerivative(localDof);
487 if constexpr (enableGridFluxVarsCache)
488 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
491 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
499 template <
class PartialReassembler = DefaultPartialReassembler>
500 void assembleJacobianExplicit_(JacobianMatrix& A, GridVariables& gridVariables,
501 const ElementResidualVector& origResiduals,
502 const PartialReassembler* partialReassembler =
nullptr)
504 if (partialReassembler)
505 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for explicit time discretization");
509 const auto& fvGeometry = this->fvGeometry();
510 const auto& curSol = this->asImp_().curSol();
511 auto&& curElemVolVars = this->curElemVolVars();
514 auto elemSol =
elementSolution(element, curSol, fvGeometry.gridGeometry());
517 ElementResidualVector partialDerivs(Dumux::Detail::LocalDofs::numLocalDofs(fvGeometry));
520 for (
const auto& scv :
scvs(fvGeometry))
523 const auto dofIdx = scv.dofIndex();
524 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
525 const VolumeVariables origVolVars(curVolVars);
528 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
532 auto evalStorage = [&](Scalar priVar)
534 elemSol[scv.localDofIndex()][pvIdx] = priVar;
535 curVolVars.update(elemSol, this->asImp_().problem(),
element, scv);
536 return this->evalStorage();
540 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
541 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(),
"Assembly.NumericDifferenceMethod");
543 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
546 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
552 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
556 curVolVars = origVolVars;
559 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
Control volume finite element local assembler using numeric differentiation.
Definition: experimental/assembly/cvfelocalassembler.hh:340
void assembleJacobian(JacobianMatrix &A, GridVariables &gridVariables, const ElementResidualVector &origResiduals, const PartialReassembler *partialReassembler=nullptr)
Definition: experimental/assembly/cvfelocalassembler.hh:364
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: experimental/assembly/cvfelocalassembler.hh:360
typename ParentType::LocalResidual LocalResidual
Definition: experimental/assembly/cvfelocalassembler.hh:359
A base class for all local CVFE assemblers.
Definition: experimental/assembly/cvfelocalassembler.hh:54
void assembleJacobian(JacobianMatrix &jac, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: experimental/assembly/cvfelocalassembler.hh:202
void bindLocalViews()
Definition: experimental/assembly/cvfelocalassembler.hh:73
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition: experimental/assembly/cvfelocalassembler.hh:226
void assembleJacobianAndResidual(JacobianMatrix &jac, ResidualVector &res, GridVariables &gridVariables, const StageParams &stageParams, ResidualVector &temporal, ResidualVector &spatial, ResidualVector &constrainedDofs, const PartialReassembler *partialReassembler=nullptr, const CouplingFunction &maybeAssembleCouplingBlocks=noop)
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition: experimental/assembly/cvfelocalassembler.hh:84
typename ParentType::LocalResidual LocalResidual
Definition: experimental/assembly/cvfelocalassembler.hh:69
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: experimental/assembly/cvfelocalassembler.hh:70
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition: experimental/assembly/cvfelocalassembler.hh:275
void assembleCurrentResidual(ResidualVector &spatialRes, ResidualVector &temporalRes)
Assemble the residual only.
Definition: experimental/assembly/cvfelocalassembler.hh:249
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition: experimental/assembly/cvfelocalassembler.hh:308
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition: experimental/assembly/cvfelocalassembler.hh:315
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition: experimental/assembly/cvfelocalassembler.hh:263
An assembler for Jacobian and residual contribution per element (CVFE methods)
Definition: experimental/assembly/cvfelocalassembler.hh:328
A base class for all local assemblers.
Definition: experimental/assembly/fvlocalassemblerbase.hh:38
ElementVolumeVariables & curElemVolVars()
The current element volume variables.
Definition: experimental/assembly/fvlocalassemblerbase.hh:234
void bindLocalViews()
Convenience function bind and prepare all relevant variables required for the evaluation of the local...
Definition: experimental/assembly/fvlocalassemblerbase.hh:163
ElementResidualVector evalLocalResidual() const
Convenience function to evaluate the complete local residual for the current element....
Definition: experimental/assembly/fvlocalassemblerbase.hh:104
bool elementIsGhost() const
Returns if element is a ghost entity.
Definition: experimental/assembly/fvlocalassemblerbase.hh:222
ElementResidualVector evalLocalFluxAndSourceResidual() const
Convenience function to evaluate the flux and source terms (i.e, the terms without a time derivative)...
Definition: experimental/assembly/fvlocalassemblerbase.hh:133
const Problem & problem() const
The problem.
Definition: experimental/assembly/fvlocalassemblerbase.hh:210
LocalResidual & localResidual()
The local residual for the current element.
Definition: experimental/assembly/fvlocalassemblerbase.hh:242
const Element & element() const
The current element.
Definition: experimental/assembly/fvlocalassemblerbase.hh:218
FVElementGeometry & fvGeometry()
The global finite volume geometry.
Definition: experimental/assembly/fvlocalassemblerbase.hh:230
Implementation & asImp_()
Definition: experimental/assembly/fvlocalassemblerbase.hh:274
ElementBoundaryTypes & elemBcTypes()
The element's boundary types.
Definition: experimental/assembly/fvlocalassemblerbase.hh:246
std::decay_t< decltype(std::declval< Assembler >().localResidual())> LocalResidual
Definition: experimental/assembly/fvlocalassemblerbase.hh:57
Base class for grid variables.
Definition: experimental/discretization/gridvariables.hh:33
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
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: experimental/assembly/cclocalassembler.hh:36
constexpr auto noop
Function that performs no operation.
Definition: common/typetraits/typetraits.hh:29
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.