25#ifndef DUMUX_FC_LOCAL_ASSEMBLER_HH
26#define DUMUX_FC_LOCAL_ASSEMBLER_HH
28#include <dune/grid/common/gridenums.hh>
46 template<
class... Args>
50template<
class T,
class Default>
64template<
class TypeTag,
class Assembler,
class Implementation,
bool implicit>
78 using ParentType::ParentType;
90 template <
class PartialReassembler = DefaultPartialReassembler,
class CouplingFunction = Detail::NoOpFunctor>
93 const CouplingFunction& maybeAssembleCouplingBlocks = CouplingFunction{})
95 static_assert(!std::decay_t<
decltype(this->
asImp_().problem())>::enableInternalDirichletConstraints(),
96 "Internal Dirichlet constraints are currently not implemented for face-centered staggered models!");
98 this->
asImp_().bindLocalViews();
99 const auto& gridGeometry = this->
asImp_().problem().gridGeometry();
100 const auto eIdxGlobal = gridGeometry.elementMapper().index(this->
element());
101 if (partialReassembler
104 const auto residual = this->
asImp_().evalLocalResidual();
105 for (
const auto& scv : scvs(this->
fvGeometry()))
106 res[scv.dofIndex()] += residual[scv.localDofIndex()];
109 maybeAssembleCouplingBlocks(residual);
113 const auto residual = this->
asImp_().assembleJacobianAndResidualImpl(jac, gridVariables, partialReassembler);
115 if (this->
element().partitionType() == Dune::InteriorEntity)
117 for (
const auto& scv : scvs(this->
fvGeometry()))
118 res[scv.dofIndex()] += residual[scv.localDofIndex()];
123 for (
const auto& scv : scvs(this->
fvGeometry()))
125 const auto& facet = this->
element().template subEntity <1> (scv.indexInElement());
128 if (facet.partitionType() == Dune::BorderEntity)
129 res[scv.dofIndex()] += residual[scv.localDofIndex()];
135 const auto idx = scv.dofIndex();
137 for (
int i = 0; i < jac[idx][idx].size(); ++i)
138 jac[idx][idx][i][i] = 1.0;
145 maybeAssembleCouplingBlocks(residual);
148 DUNE_THROW(Dune::NotImplemented,
"Ghost elements not supported");
151 auto applyDirichlet = [&] (
const auto& scvI,
152 const auto& dirichletValues,
156 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[pvIdx] - dirichletValues[pvIdx];
158 auto& row = jac[scvI.dofIndex()];
159 for (
auto col = row.begin(); col != row.end(); ++col)
160 row[col.index()][eqIdx] = 0.0;
162 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
175 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
184 this->
asImp_().bindLocalViews();
185 this->
asImp_().assembleJacobianAndResidualImpl(jac, gridVariables);
187 auto applyDirichlet = [&] (
const auto& scvI,
188 const auto& dirichletValues,
192 auto& row = jac[scvI.dofIndex()];
193 for (
auto col = row.begin(); col != row.end(); ++col)
194 row[col.index()][eqIdx] = 0.0;
196 jac[scvI.dofIndex()][scvI.dofIndex()][eqIdx][pvIdx] = 1.0;
199 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
207 this->
asImp_().bindLocalViews();
210 for (
const auto& scv : scvs(this->
fvGeometry()))
211 res[scv.dofIndex()] += residual[scv.localDofIndex()];
213 auto applyDirichlet = [&] (
const auto& scvI,
214 const auto& dirichletValues,
218 res[scvI.dofIndex()][eqIdx] = this->
curElemVolVars()[scvI].priVars()[eqIdx] - dirichletValues[pvIdx];
221 this->
asImp_().enforceDirichletConstraints(applyDirichlet);
227 template<
typename ApplyFunction>
231 this->
asImp_().evalDirichletBoundaries(applyDirichlet);
233 this->
asImp_().enforceInternalDirichletConstraints(applyDirichlet);
239 template<
typename ApplyDirichletFunctionType >
246 for (
const auto& scvf : scvfs(this->
fvGeometry()))
248 if (scvf.isFrontal() && scvf.boundary())
250 const auto bcTypes = this->
elemBcTypes()[scvf.localIndex()];
251 if (bcTypes.hasDirichlet())
253 const auto& scv = this->
fvGeometry().scv(scvf.insideScvIdx());
254 const auto dirichletValues = this->
asImp_().problem().dirichlet(this->
element(), scvf);
257 for (
int eqIdx = 0; eqIdx < numEq; ++eqIdx)
259 for (
int pvIdx = 0; pvIdx < GridView::dimension; ++pvIdx)
261 if (bcTypes.isDirichlet(pvIdx) && pvIdx == scv.dofAxis())
262 applyDirichlet(scv, dirichletValues, eqIdx, pvIdx);
275 template<
class... Args>
282 template<
class... Args>
294template<
class TypeTag,
class Assembler, DiffMethod diffMethod = DiffMethod::numeric,
bool implicit = true,
class Implementation =
void>
302template<
class TypeTag,
class Assembler,
class Implementation>
305 Detail::NonVoidOrDefault_t<Implementation, FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, true, Implementation>>, true>
312 using FVElementGeometry =
typename GridGeometry::LocalView;
313 using SubControlVolume =
typename FVElementGeometry::SubControlVolume;
314 using SubControlVolumeFace =
typename FVElementGeometry::SubControlVolumeFace;
320 static constexpr bool enableGridFluxVarsCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
334 template <
class PartialReassembler = DefaultPartialReassembler>
339 const auto& problem = this->asImp_().problem();
340 const auto& element = this->element();
341 const auto& fvGeometry = this->fvGeometry();
342 const auto& curSol = this->asImp_().curSol();
344 auto&& curElemVolVars = this->curElemVolVars();
347 const auto origResiduals = this->evalLocalResidual();
358 const auto numElementResiduals = element.subEntities(1);
365 this->localResidual().evalSource(residual, problem, element, fvGeometry, curElemVolVars, scv);
370 this->localResidual().evalStorage(residual, problem, element, fvGeometry, this->prevElemVolVars(), curElemVolVars, scv);
375 if (!scvf.processorBoundary())
376 this->localResidual().evalFlux(residual, problem, element, fvGeometry, curElemVolVars, this->elemBcTypes(), this->elemFluxVarsCache(), scvf);
379 const auto evalDerivative = [&] (
const auto& scvI,
const auto& scvJ)
382 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
385 const auto& otherElement = fvGeometry.gridGeometry().element(scvJ.elementIndex());
386 auto otherElemSol =
elementSolution(otherElement, curSol, fvGeometry.gridGeometry());
387 auto& curOtherVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scvJ);
388 const VolumeVariables origOtherVolVars(curOtherVolVars);
390 auto evalResiduals = [&](Scalar priVar)
393 otherElemSol[scvJ.localDofIndex()][pvIdx] = priVar;
394 curOtherVolVars.update(otherElemSol, problem, otherElement, scvJ);
395 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
400 evalSource(residual, scvI);
402 if (!this->assembler().isStationaryProblem())
403 evalStorage(residual, scvI);
405 for (
const auto& scvf : scvfs(fvGeometry, scvI))
406 evalFlux(residual, scvf);
413 static const int numDiffMethod = getParamFromGroup<int>(this->asImp_().problem().paramGroup(),
"Assembly.NumericDifferenceMethod");
415 eps_(otherElemSol[scvJ.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
417 const auto updateJacobian = [&]()
419 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
425 A[scvI.dofIndex()][scvJ.dofIndex()][eqIdx][pvIdx] += partialDerivs[scvI.localDofIndex()][eqIdx];
429 using GeometryHelper =
typename std::decay_t<
decltype(fvGeometry.gridGeometry())>::GeometryHelper;
430 using LocalIntersectionMapper =
typename std::decay_t<
decltype(fvGeometry.gridGeometry())>::LocalIntersectionMapper;
431 LocalIntersectionMapper localIsMapper;
433 const bool isParallel = fvGeometry.gridGeometry().gridView().comm().size() > 1;
435 localIsMapper.update(fvGeometry.gridGeometry().gridView(), element);
437 if (element.partitionType() == Dune::InteriorEntity)
441 const auto localIdxI = scvI.indexInElement();
442 const auto localIdxJ = scvJ.indexInElement();
444 const auto& facetI = GeometryHelper::facet(localIsMapper.refToRealIdx(localIdxI), element);
446 if (facetI.partitionType() == Dune::BorderEntity &&
447 (localIdxJ == GeometryHelper::localOppositeIdx(localIdxI) || scvJ.dofIndex() == scvI.dofIndex()))
451 if (isParallel && element.partitionType() == Dune::InteriorEntity)
453 const auto localIdxI = scvI.indexInElement();
454 const auto& facetI = GeometryHelper::facet(localIsMapper.refToRealIdx(localIdxI), element);
455 if (facetI.partitionType() == Dune::BorderEntity)
457 for (
const auto& scvf : scvfs(fvGeometry, scvI))
459 if (scvf.isFrontal() || scvf.boundary())
463 if (scvf.outsideScvIdx() == scvJ.index())
468 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
469 if (orthogonalScvf.boundary())
472 if (orthogonalScvf.insideScvIdx() == scvJ.index() || orthogonalScvf.outsideScvIdx() == scvJ.index())
480 curOtherVolVars = origOtherVolVars;
483 otherElemSol[scvJ.localDofIndex()][pvIdx] = curSol[scvJ.dofIndex()][pvIdx];
484 this->asImp_().maybeUpdateCouplingContext(scvJ, otherElemSol, pvIdx);
490 for (
const auto& scvI : scvs(fvGeometry))
493 evalDerivative(scvI, scvI);
496 const auto& otherScvIndices = fvGeometry.gridGeometry().connectivityMap()[scvI.index()];
497 for (
const auto globalJ : otherScvIndices)
498 evalDerivative(scvI, fvGeometry.scv(globalJ));
502 this->asImp_().maybeEvalAdditionalDomainDerivatives(origResiduals, A, gridVariables);
504 return origResiduals;
514template<
class TypeTag,
class Assembler>
517 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, false>, false>
526 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
540 template <
class PartialReassembler = DefaultPartialReassembler>
544 if (partialReassembler)
545 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for explicit time discretization");
548 const auto& element = this->element();
549 const auto& fvGeometry = this->fvGeometry();
550 const auto& curSol = this->curSol();
551 auto&& curElemVolVars = this->curElemVolVars();
554 const auto origResiduals = this->evalLocalResidual();
555 const auto origStorageResiduals = this->evalLocalStorageResidual();
566 auto elemSol =
elementSolution(element, curSol, fvGeometry.gridGeometry());
569 ElementResidualVector partialDerivs(element.subEntities(1));
572 for (
auto&& scv : scvs(fvGeometry))
575 const auto dofIdx = scv.dofIndex();
576 auto& curVolVars = this->getVolVarAccess(gridVariables.curGridVolVars(), curElemVolVars, scv);
577 const VolumeVariables origVolVars(curVolVars);
580 for (
int pvIdx = 0; pvIdx < numEq; pvIdx++)
584 auto evalStorage = [&](Scalar priVar)
587 elemSol[scv.localDofIndex()][pvIdx] = priVar;
588 curVolVars.update(elemSol, this->problem(), element, scv);
589 return this->evalLocalStorageResidual();
594 static const int numDiffMethod = getParamFromGroup<int>(this->problem().paramGroup(),
"Assembly.NumericDifferenceMethod");
596 eps_(elemSol[scv.localDofIndex()][pvIdx], pvIdx), numDiffMethod);
599 for (
int eqIdx = 0; eqIdx < numEq; eqIdx++)
605 A[dofIdx][dofIdx][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
609 curVolVars = origVolVars;
612 elemSol[scv.localDofIndex()][pvIdx] = curSol[scv.dofIndex()][pvIdx];
616 return origResiduals;
625template<
class TypeTag,
class Assembler>
628 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, true>, true>
635 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
649 template <
class PartialReassembler = DefaultPartialReassembler>
653 if (partialReassembler)
654 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for analytic differentiation");
657 const auto& element = this->element();
658 const auto& fvGeometry = this->fvGeometry();
659 const auto& problem = this->problem();
660 const auto& curElemVolVars = this->curElemVolVars();
661 const auto& elemFluxVarsCache = this->elemFluxVarsCache();
664 const auto origResiduals = this->evalLocalResidual();
675 for (
const auto& scv : scvs(fvGeometry))
678 const auto dofIdx = scv.dofIndex();
679 const auto& volVars = curElemVolVars[scv];
684 if (!this->assembler().isStationaryProblem())
685 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
694 this->localResidual().addSourceDerivatives(A[dofIdx][dofIdx],
703 for (
const auto& scvf : scvfs(fvGeometry))
705 if (!scvf.boundary())
708 this->localResidual().addFluxDerivatives(A,
721 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
722 if (this->elemBcTypes()[insideScv.localDofIndex()].hasNeumann())
725 this->localResidual().addRobinFluxDerivatives(A[insideScv.dofIndex()],
736 return origResiduals;
745template<
class TypeTag,
class Assembler>
748 FaceCenteredLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, false>, false>
755 using ElementResidualVector =
typename LocalResidual::ElementResidualVector;
769 template <
class PartialReassembler = DefaultPartialReassembler>
773 if (partialReassembler)
774 DUNE_THROW(Dune::NotImplemented,
"partial reassembly for explicit time discretization");
777 const auto& element = this->element();
778 const auto& fvGeometry = this->fvGeometry();
779 const auto& problem = this->problem();
780 const auto& curElemVolVars = this->curElemVolVars();
783 const auto origResiduals = this->evalLocalResidual();
794 for (
const auto& scv : scvs(fvGeometry))
797 const auto dofIdx = scv.dofIndex();
798 const auto& volVars = curElemVolVars[scv];
802 this->localResidual().addStorageDerivatives(A[dofIdx][dofIdx],
810 return origResiduals;
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.
An adapter class for local assemblers using numeric differentiation.
Detects which entries in the Jacobian have to be recomputed.
A class for numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::box, BoxElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for box schemes.
Definition: box/elementsolution.hh:118
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition: diffmethod.hh:37
@ green
does not need to be reassembled
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
std::conditional_t<!std::is_same_v< T, void >, T, Default > NonVoidOrDefault_t
Definition: fclocalassembler.hh:51
Definition: fclocalassembler.hh:45
constexpr void operator()(Args &&...) const
Definition: fclocalassembler.hh:47
A base class for all local cell-centered assemblers.
Definition: fclocalassembler.hh:66
void enforceDirichletConstraints(const ApplyFunction &applyDirichlet)
Enforce Dirichlet constraints.
Definition: fclocalassembler.hh:228
void assembleResidual(SolutionVector &res)
Assemble the residual only.
Definition: fclocalassembler.hh:205
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:182
void assembleJacobianAndResidual(JacobianMatrix &jac, SolutionVector &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:91
void maybeUpdateCouplingContext(Args &&...)
Update the coupling context for coupled models.
Definition: fclocalassembler.hh:276
void bindLocalViews()
Definition: fclocalassembler.hh:80
void evalDirichletBoundaries(ApplyDirichletFunctionType applyDirichlet)
Evaluates Dirichlet boundaries.
Definition: fclocalassembler.hh:240
void maybeEvalAdditionalDomainDerivatives(Args &&...)
Update the additional domain derivatives for coupled models.
Definition: fclocalassembler.hh:283
An assembler for Jacobian and residual contribution per element (Face-centered methods)
Definition: fclocalassembler.hh:295
Face-centered scheme local assembler using numeric differentiation and implicit time discretization.
Definition: fclocalassembler.hh:306
typename LocalResidual::ElementResidualVector ElementResidualVector
Definition: fclocalassembler.hh:325
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: fclocalassembler.hh:335
GetPropType< TypeTag, Properties::LocalResidual > LocalResidual
Definition: fclocalassembler.hh:324
TODO docme.
Definition: fclocalassembler.hh:518
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: fclocalassembler.hh:541
TODO docme.
Definition: fclocalassembler.hh:629
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: fclocalassembler.hh:650
TODO docme.
Definition: fclocalassembler.hh:749
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: fclocalassembler.hh:770
A base class for all local assemblers.
Definition: fvlocalassemblerbase.hh:48
void bindLocalViews()
Convenience function bind and prepare all relevant variables required for the evaluation of the local...
Definition: fvlocalassemblerbase.hh:185
ElementVolumeVariables & curElemVolVars()
The current element volume variables.
Definition: fvlocalassemblerbase.hh:265
ElementBoundaryTypes & elemBcTypes()
The element's boundary types.
Definition: fvlocalassemblerbase.hh:281
Implementation & asImp_()
Definition: fvlocalassemblerbase.hh:309
ElementResidualVector evalLocalResidual() const
Convenience function to evaluate the complete local residual for the current element....
Definition: fvlocalassemblerbase.hh:120
const Problem & problem() const
The problem.
Definition: fvlocalassemblerbase.hh:241
FVElementGeometry & fvGeometry()
The global finite volume geometry.
Definition: fvlocalassemblerbase.hh:261
bool elementIsGhost() const
Returns if element is a ghost entity.
Definition: fvlocalassemblerbase.hh:253
const Element & element() const
The current element.
Definition: fvlocalassemblerbase.hh:249
A helper class for local assemblers using numeric differentiation to determine the epsilon.
Definition: numericepsilon.hh:41
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:432
EntityColor elementColor(size_t idx) const
Definition: partialreassembler.hh:503
static void partialDerivative(const Function &function, Scalar x0, FunctionEvalType &derivative, const FunctionEvalType &fx0, const int numericDifferenceMethod=1)
Computes the derivative of a function with repect to a function parameter.
Definition: numericdifferentiation.hh:61
Declares all properties used in Dumux.