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