13#ifndef DUMUX_FC_LOCAL_ASSEMBLER_HH
14#define DUMUX_FC_LOCAL_ASSEMBLER_HH
16#include <dune/grid/common/gridenums.hh>
34 template<
class... Args>
38template<
class T,
class Default>
52template<
class TypeTag,
class Assembler,
class Implementation,
bool implicit>
66 using ParentType::ParentType;
78 template <
class Res
idualVector,
class PartialReassembler = DefaultPartialReassembler,
class CouplingFunction = Detail::NoOpFunctor>
81 const CouplingFunction& maybeAssembleCouplingBlocks = CouplingFunction{})
83 static_assert(!std::decay_t<
decltype(this->
asImp_().problem())>::enableInternalDirichletConstraints(),
84 "Internal Dirichlet constraints are currently not implemented for face-centered staggered models!");
86 this->
asImp_().bindLocalViews();
87 const auto& gridGeometry = this->
asImp_().problem().gridGeometry();
88 const auto eIdxGlobal = gridGeometry.elementMapper().index(this->
element());
89 if (partialReassembler
92 const auto residual = this->
asImp_().evalLocalResidual();
93 for (
const auto& scv : scvs(this->
fvGeometry()))
94 res[scv.dofIndex()] += residual[scv.localDofIndex()];
97 maybeAssembleCouplingBlocks(residual);
101 const auto residual = this->
asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler);
103 if (this->
element().partitionType() == Dune::InteriorEntity)
105 for (
const auto& scv : scvs(this->
fvGeometry()))
106 res[scv.dofIndex()] += residual[scv.localDofIndex()];
111 for (
const auto& scv : scvs(this->
fvGeometry()))
113 const auto& facet = this->
element().template subEntity <1> (scv.indexInElement());
116 if (facet.partitionType() == Dune::BorderEntity)
117 res[scv.dofIndex()] += residual[scv.localDofIndex()];
123 const auto idx = scv.dofIndex();
125 for (
int i = 0; i < jac[idx][idx].size(); ++i)
126 jac[idx][idx][i][i] = 1.0;
133 maybeAssembleCouplingBlocks(residual);
136 DUNE_THROW(Dune::NotImplemented,
"Ghost elements not supported");
139 auto applyDirichlet = [&] (
const auto& scvI,
140 const auto& dirichletValues,
144 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
146 auto& row = jac[scvI.dofIndex()];
147 for (
auto col = row.begin(); col != row.end(); ++col)
148 row[col.index()][eqIdx] = 0.0;
150 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
153 if (this->
asImp_().
problem().gridGeometry().dofOnPeriodicBoundary(scvI.dofIndex()))
155 const auto periodicDof = this->
asImp_().problem().gridGeometry().periodicallyMappedDof(scvI.dofIndex());
156 res[periodicDof][eqIdx] = this->
asImp_().curSol()[periodicDof][pvIdx] - dirichletValues[pvIdx];
158 auto& rowP = jac[periodicDof];
159 for (
auto col = rowP.begin(); col != rowP.end(); ++col)
160 row[col.index()][eqIdx] = 0.0;
162 rowP[periodicDof][eqIdx][pvIdx] = 1.0;
166 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
175 this->
asImp_().bindLocalViews();
176 this->
asImp_().assembleJacobianAndResidualImpl(jac, gridVariables);
178 auto applyDirichlet = [&] (
const auto& scvI,
179 const auto& dirichletValues,
183 auto& row = jac[scvI.dofIndex()];
184 for (
auto col = row.begin(); col != row.end(); ++col)
185 row[col.index()][eqIdx] = 0.0;
187 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
190 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
196 template<
class Res
idualVector>
199 this->
asImp_().bindLocalViews();
202 for (
const auto& scv : scvs(this->
fvGeometry()))
203 res[scv.dofIndex()] += residual[scv.localDofIndex()];
205 auto applyDirichlet = [&] (
const auto& scvI,
206 const auto& dirichletValues,
210 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
213 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
219 template<
typename ApplyFunction>
223 this->
asImp_().evalDirichletBoundaries(applyDirichlet);
225 this->
asImp_().enforceInternalDirichletConstraints(applyDirichlet);
231 template<
typename ApplyDirichletFunctionType >
238 for (
const auto& scvf : scvfs(this->
fvGeometry()))
240 if (scvf.isFrontal() && scvf.boundary())
242 const auto bcTypes = this->
elemBcTypes()[scvf.localIndex()];
243 if (bcTypes.hasDirichlet())
245 const auto& scv = this->
fvGeometry().scv(scvf.insideScvIdx());
246 const auto dirichletValues = this->
asImp_().problem().dirichlet(this->
element(), scvf);
249 for (
int eqIdx = 0; eqIdx < numEq; ++eqIdx)
251 static_assert(numEq == 1,
"Not yet implemented for more than one vector-valued primary variable");
252 const int pvIdx = eqIdx;
253 const int componentIdx = scv.dofAxis();
254 if (bcTypes.isDirichlet(componentIdx))
255 applyDirichlet(scv, std::array<Scalar,1>{{dirichletValues[componentIdx]}}, eqIdx, pvIdx);
267 template<
class... Args>
274 template<
class... Args>
287template<
class TypeTag,
class Assembler, DiffMethod diffMethod = DiffMethod::numeric,
bool implicit = true,
class Implementation =
void>
295template<
class TypeTag,
class Assembler,
class Implementation>
299 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>,
308 using FVElementGeometry =
typename GridGeometry::LocalView;
309 using SubControlVolume =
typename FVElementGeometry::SubControlVolume;
310 using SubControlVolumeFace =
typename FVElementGeometry::SubControlVolumeFace;
320 using LocalResidual =
typename ParentType::LocalResidual;
321 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
322 using ParentType::ParentType;
330 template <
class PartialReassembler = DefaultPartialReassembler>
331 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
335 const auto& problem = this->asImp_().problem();
336 const auto& element = this->element();
337 const auto& fvGeometry = this->fvGeometry();
338 const auto& curSol = this->asImp_().curSol();
339 auto&& curElemVolVars = this->curElemVolVars();
342 const auto origResiduals = this->evalLocalResidual();
353 const auto numElementResiduals = fvGeometry.numScv();
356 ElementResidualVector partialDerivs(numElementResiduals);
358 const auto evalSource = [&](ElementResidualVector& residual,
const SubControlVolume& scv)
360 this->localResidual().evalSource(residual, problem, element, fvGeometry, curElemVolVars, scv);
363 const auto evalStorage = [&](ElementResidualVector& residual,
const SubControlVolume& scv)
365 this->localResidual().evalStorage(residual, problem, element, fvGeometry, this->prevElemVolVars(), curElemVolVars, scv);
368 const auto evalFlux = [&](ElementResidualVector& residual,
const SubControlVolumeFace& scvf)
370 if (!scvf.processorBoundary())
371 this->localResidual().evalFlux(residual, problem, element, fvGeometry, curElemVolVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
374 const auto evalDerivative = [&] (
const auto& scvI,
const auto& scvJ)
377 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
380 const auto& otherElement = fvGeometry.gridGeometry().element(scvJ.elementIndex());
381 auto otherElemSol =
elementSolution(otherElement, curSol, fvGeometry.gridGeometry());
382 auto& curOtherVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
383 const VolumeVariables origOtherVolVars(curOtherVolVars);
385 auto evalResiduals = [&](Scalar priVar)
388 otherElemSol[scvJ.localDofIndex()][pvIdx] = priVar;
389 curOtherVolVars.update(otherElemSol, problem, otherElement, scvJ);
390 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
392 ElementResidualVector residual(numElementResiduals);
395 evalSource(residual, scvI);
397 if (!this->assembler().isStationaryProblem())
398 evalStorage(residual, scvI);
400 for (
const auto& scvf : scvfs(fvGeometry, scvI))
401 evalFlux(residual, scvf);
407 static const NumericEpsilon<Scalar, numEq> eps_{this->asImp_().problem().paramGroup()};
408 static const int numDiffMethod =
getParamFromGroup<int>(this->asImp_().problem().paramGroup(),
"Assembly.NumericDifferenceMethod");
410 eps_(otherElemSol[scvJ.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
412 const auto updateJacobian = [&]()
414 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
420 A[scvI.dofIndex()][scvJ.dofIndex()][eqIdx][pvIdx] += partialDerivs[scvI.localDofIndex()][eqIdx];
424 if (
element.partitionType() == Dune::InteriorEntity)
428 const auto localIdxI = scvI.indexInElement();
429 const auto& facetI =
element.template subEntity <1> (localIdxI);
431 if (facetI.partitionType() == Dune::BorderEntity)
436 curOtherVolVars = origOtherVolVars;
439 otherElemSol[scvJ.localDofIndex()][pvIdx] = curSol[scvJ.dofIndex()][pvIdx];
440 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
446 for (
const auto& scvI : scvs(fvGeometry))
449 evalDerivative(scvI, scvI);
452 const auto& otherScvIndices = fvGeometry.gridGeometry().connectivityMap()[scvI.index()];
453 for (
const auto globalJ : otherScvIndices)
454 evalDerivative(scvI, fvGeometry.scv(globalJ));
458 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
460 return origResiduals;
470template<
class TypeTag,
class Assembler,
class Implementation>
474 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>>,
478 using ThisType = FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false, Implementation>;
479 using ParentType = FaceCenteredLocalAssemblerBase<TypeTag, Assembler, Detail::NonVoidOrDefault_t<Implementation, ThisType>,
false>;
481 using Element =
typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
486 enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
489 using LocalResidual =
typename ParentType::LocalResidual;
490 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
491 using ParentType::ParentType;
499 template <
class PartialReassembler = DefaultPartialReassembler>
500 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
501 const PartialReassembler* partialReassembler =
nullptr)
503 if (partialReassembler)
504 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for explicit time discretization");
507 const auto& problem = this->asImp_().problem();
509 const auto& fvGeometry = this->fvGeometry();
510 const auto& curSol = this->asImp_().curSol();
511 auto&& curElemVolVars = this->curElemVolVars();
514 const auto origResiduals = this->evalLocalResidual();
515 const auto origStorageResiduals = this->evalLocalStorageResidual();
526 auto elemSol =
elementSolution(element, curSol, fvGeometry.gridGeometry());
529 ElementResidualVector partialDerivs(fvGeometry.numScv());
532 for (
const auto& scv : scvs(fvGeometry))
535 const auto dofIdx = scv.dofIndex();
536 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
537 const VolumeVariables origVolVars(curVolVars);
540 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
544 auto evalStorage = [&](Scalar priVar)
547 elemSol[scv.localDofIndex()][pvIdx] = priVar;
548 curVolVars.update(elemSol, problem, element, scv);
549 return this->evalLocalStorageResidual();
553 static const NumericEpsilon<Scalar, numEq> eps_{problem.paramGroup()};
554 static const int numDiffMethod =
getParamFromGroup<int>(problem.paramGroup(),
"Assembly.NumericDifferenceMethod");
556 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
559 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
565 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
569 curVolVars = origVolVars;
572 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
575 return origResiduals;
584template<
class TypeTag,
class Assembler,
class Implementation>
588 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>,
592 using ThisType = FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true, Implementation>;
593 using ParentType = FaceCenteredLocalAssemblerBase<TypeTag, Assembler, Detail::NonVoidOrDefault_t<Implementation, ThisType>,
true>;
598 enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
601 using LocalResidual =
typename ParentType::LocalResidual;
602 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
603 using ParentType::ParentType;
611 template <
class PartialReassembler = DefaultPartialReassembler>
612 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
613 const PartialReassembler* partialReassembler =
nullptr)
615 if (partialReassembler)
616 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for analytic differentiation");
620 const auto& fvGeometry = this->fvGeometry();
621 const auto& problem = this->asImp_().problem();
622 const auto& curElemVolVars = this->curElemVolVars();
623 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
626 const auto origResiduals = this->evalLocalResidual();
637 for (
const auto& scv : scvs(fvGeometry))
640 const auto dofIdx = scv.dofIndex();
641 const auto& volVars = curElemVolVars[scv];
646 if (!this->assembler().isStationaryProblem())
647 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
656 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
665 for (
const auto& scvf : scvfs(fvGeometry))
667 if (!scvf.boundary())
670 this->localResidual().addFluxDerivatives(A,
683 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
684 if (this->elemBcTypes()[insideScv.localDofIndex()].hasNeumann())
687 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
698 return origResiduals;
707template<
class TypeTag,
class Assembler,
class Implementation>
711 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>,
715 using ThisType = FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false, Implementation>;
716 using ParentType = FaceCenteredLocalAssemblerBase<TypeTag, Assembler, Detail::NonVoidOrDefault_t<Implementation, ThisType>,
false>;
721 enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
724 using LocalResidual =
typename ParentType::LocalResidual;
725 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
726 using ParentType::ParentType;
734 template <
class PartialReassembler = DefaultPartialReassembler>
735 ElementResidualVector assembleJacobianAndResidualImpl(JacobianMatrix& A, GridVariables& gridVariables,
736 const PartialReassembler* partialReassembler =
nullptr)
738 if (partialReassembler)
739 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for explicit time discretization");
743 const auto& fvGeometry = this->fvGeometry();
744 const auto& problem = this->asImp_().problem();
745 const auto& curElemVolVars = this->curElemVolVars();
748 const auto origResiduals = this->evalLocalResidual();
759 for (
const auto& scv : scvs(fvGeometry))
762 const auto dofIdx = scv.dofIndex();
763 const auto& volVars = curElemVolVars[scv];
767 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
775 return origResiduals;
A base class for all local assemblers.
void bindLocalViews()
Definition assembly/fvlocalassemblerbase.hh:173
ElementVolumeVariables & curElemVolVars()
Definition assembly/fvlocalassemblerbase.hh:253
ElementBoundaryTypes & elemBcTypes()
Definition assembly/fvlocalassemblerbase.hh:269
Implementation & asImp_()
Definition assembly/fvlocalassemblerbase.hh:297
ElementResidualVector evalLocalResidual() const
Definition assembly/fvlocalassemblerbase.hh:108
const Problem & problem() const
Definition assembly/fvlocalassemblerbase.hh:229
FVLocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol)
Definition assembly/fvlocalassemblerbase.hh:61
FVElementGeometry & fvGeometry()
Definition assembly/fvlocalassemblerbase.hh:249
bool elementIsGhost() const
Definition assembly/fvlocalassemblerbase.hh:241
const Element & element() const
Definition assembly/fvlocalassemblerbase.hh:237
A base class for all local cell-centered assemblers.
Definition fclocalassembler.hh:54
void assembleJacobianAndResidual(JacobianMatrix &jac, ResidualVector &res, GridVariables &gridVariables, const PartialReassembler *partialReassembler, const CouplingFunction &maybeAssembleCouplingBlocks=CouplingFunction{})
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition fclocalassembler.hh:79
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition fclocalassembler.hh:220
void assembleJacobian(JacobianMatrix &jac, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition fclocalassembler.hh:173
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition fclocalassembler.hh:268
void bindLocalViews()
Definition fclocalassembler.hh:68
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition fclocalassembler.hh:232
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition fclocalassembler.hh:275
void assembleResidual(ResidualVector &res)
Assemble the residual only.
Definition fclocalassembler.hh:197
An assembler for Jacobian and residual contribution per element (Face-centered methods)
Definition fclocalassembler.hh:288
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
EntityColor elementColor(size_t idx) const
Definition partialreassembler.hh:491
Defines all properties used in Dumux.
An enum class to define various differentiation methods available in order to compute the derivatives...
An enum class to define the colors of elements and vertices required for partial Jacobian reassembly.
The global face variables class for staggered models.
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition diffmethod.hh:25
@ analytic
Definition diffmethod.hh:26
@ numeric
Definition diffmethod.hh:26
@ green
does not need to be reassembled
Definition entitycolor.hh:40
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::cctpfa||GridGeometry::discMethod==DiscretizationMethods::ccmpfa, CCElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for cell-centered schemes.
Definition cellcentered/elementsolution.hh:101
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition propertysystem.hh:296
Distance implementation details.
Definition cvfelocalresidual.hh:25
std::conditional_t<!std::is_same_v< T, void >, T, Default > NonVoidOrDefault_t
Definition fclocalassembler.hh:39
A class for numeric differentiation.
An adapter class for local assemblers using numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Detects which entries in the Jacobian have to be recomputed.
Definition fclocalassembler.hh:33
constexpr void operator()(Args &&...) const
Definition fclocalassembler.hh:35