version 3.11-dev
multidomain/subdomaincvfelocalassembler.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//
14#ifndef DUMUX_MULTIDOMAIN_SUBDOMAIN_CVFE_LOCAL_ASSEMBLER_HH
15#define DUMUX_MULTIDOMAIN_SUBDOMAIN_CVFE_LOCAL_ASSEMBLER_HH
16
17#include <type_traits>
18
19#include <dune/common/reservedvector.hh>
20#include <dune/common/indices.hh>
21#include <dune/common/hybridutilities.hh>
22#include <dune/grid/common/gridenums.hh> // for GhostEntity
23#include <dune/istl/matrixindexset.hh>
24
25#include <dumux/common/typetraits/localdofs_.hh>
26#include <dumux/common/typetraits/boundary_.hh>
37
38namespace Dumux {
39
51template<std::size_t id, class TypeTag, class Assembler, class Implementation, DiffMethod dm, bool implicit>
52class SubDomainCVFELocalAssemblerBase : public CVFELocalAssembler<TypeTag, Assembler, dm, implicit, Implementation>
53{
55
59 using SolutionVector = typename Assembler::SolutionVector;
61
63 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
64 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
65 using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
66 using Scalar = typename GridVariables::Scalar;
67
68 using GridGeometry = typename GridVariables::GridGeometry;
69 using FVElementGeometry = typename GridGeometry::LocalView;
70 using Extrusion = Extrusion_t<GridGeometry>;
71 using GridView = typename GridGeometry::GridView;
72 using Element = typename GridView::template Codim<0>::Entity;
73
74 using CouplingManager = typename Assembler::CouplingManager;
75
76 static constexpr auto numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
77
78public:
80 static constexpr auto domainId = typename Dune::index_constant<id>();
82 using ParentType::ParentType;
84 using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector;
85
86 // the constructor
88 const Assembler& assembler,
89 const Element& element,
90 const SolutionVector& curSol,
91 CouplingManager& couplingManager
92 )
93 : ParentType(assembler,
94 element,
95 curSol,
96 localView(assembler.gridGeometry(domainId)),
97 localView(assembler.gridVariables(domainId).curGridVolVars()),
98 localView(assembler.gridVariables(domainId).prevGridVolVars()),
99 localView(assembler.gridVariables(domainId).gridFluxVarsCache()),
100 assembler.localResidual(domainId),
101 (element.partitionType() == Dune::GhostEntity))
102 , couplingManager_(couplingManager)
103 {}
104
109 template<class JacobianMatrixRow, class SubResidualVector, class GridVariablesTuple>
110 void assembleJacobianAndResidual(JacobianMatrixRow& jacRow, SubResidualVector& res, GridVariablesTuple& gridVariables)
111 {
112 auto assembleCouplingBlocks = [&](const auto& residual)
113 {
114 // assemble the coupling blocks
115 using namespace Dune::Hybrid;
116 forEach(integralRange(Dune::Hybrid::size(jacRow)), [&](auto&& i)
117 {
118 if constexpr (std::decay_t<decltype(i)>{} != id)
119 this->assembleJacobianCoupling(i, jacRow, residual, gridVariables);
120 });
121 };
122
123 // the coupled model does not support partial reassembly yet
124 const DefaultPartialReassembler* noReassembler = nullptr;
125 ParentType::assembleJacobianAndResidual(jacRow[domainId], res, *std::get<domainId>(gridVariables), noReassembler, assembleCouplingBlocks);
126 }
127
132 template<std::size_t otherId, class JacRow, class GridVariables,
133 typename std::enable_if_t<(otherId == id), int> = 0>
134 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow,
135 const ElementResidualVector& res, GridVariables& gridVariables)
136 {}
137
141 template<std::size_t otherId, class JacRow, class GridVariables,
142 typename std::enable_if_t<(otherId != id), int> = 0>
143 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacRow& jacRow,
144 const ElementResidualVector& res, GridVariables& gridVariables)
145 {
146 this->asImp_().assembleJacobianCoupling(domainJ, jacRow[domainJ], res, *std::get<domainId>(gridVariables));
147 }
148
152 ElementResidualVector evalLocalSourceResidual(const Element& element, const ElementVolumeVariables& elemVolVars) const
153 {
154 static_assert(!Detail::LocalDofs::hasNonCVLocalDofsInterface<FVElementGeometry>(), "Separate source calculation not implemented for hybrid schemes.");
155
156 // initialize the residual vector for all scvs in this element
157 ElementResidualVector residual(Detail::LocalDofs::numLocalDofs(this->fvGeometry()));
158
159 // evaluate the source term
160 // forward to the local residual specialized for the discretization methods
161 for (const auto& scv : scvs(this->fvGeometry()))
162 {
163 const auto& curVolVars = elemVolVars[scv];
164 auto source = this->localResidual().computeSource(problem(), element, this->fvGeometry(), elemVolVars, scv);
165 source *= -Extrusion::volume(this->fvGeometry(), scv)*curVolVars.extrusionFactor();
166 residual[scv.localDofIndex()] = std::move(source);
167 }
168
169 return residual;
170 }
171
175 ElementResidualVector evalLocalSourceResidual(const Element& neighbor) const
176 { return this->evalLocalSourceResidual(neighbor, implicit ? this->curElemVolVars() : this->prevElemVolVars()); }
177
182 {
183 // get some references for convenience
184 const auto& element = this->element();
185 const auto& curSol = this->curSol(domainId);
186 auto&& fvGeometry = this->fvGeometry();
187 auto&& curElemVolVars = this->curElemVolVars();
188 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
189
190 // bind the caches
191 couplingManager_.bindCouplingContext(domainId, element, this->assembler());
192 fvGeometry.bind(element);
193
194 if constexpr (implicit)
195 {
196 curElemVolVars.bind(element, fvGeometry, curSol);
197 elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars);
198 if (!this->assembler().isStationaryProblem())
199 this->prevElemVolVars().bindElement(element, fvGeometry, this->assembler().prevSol()[domainId]);
200 }
201 else
202 {
203 auto& prevElemVolVars = this->prevElemVolVars();
204 const auto& prevSol = this->assembler().prevSol()[domainId];
205
206 curElemVolVars.bindElement(element, fvGeometry, curSol);
207 prevElemVolVars.bind(element, fvGeometry, prevSol);
208 elemFluxVarsCache.bind(element, fvGeometry, prevElemVolVars);
209 }
210
211 this->elemBcTypes().update(problem(), this->element(), this->fvGeometry());
212 }
213
215 template<std::size_t i = domainId>
216 const Problem& problem(Dune::index_constant<i> dId = domainId) const
217 { return this->assembler().problem(domainId); }
218
220 template<std::size_t i = domainId>
221 const auto& curSol(Dune::index_constant<i> dId = domainId) const
222 { return ParentType::curSol()[dId]; }
223
225 CouplingManager& couplingManager()
226 { return couplingManager_; }
227
228private:
229 CouplingManager& couplingManager_;
230};
231
243template<std::size_t id, class TypeTag, class Assembler, DiffMethod DM = DiffMethod::numeric, bool implicit = true>
245
252template<std::size_t id, class TypeTag, class Assembler>
253class SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>
254: public SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler,
256{
257 using ThisType = SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>;
258 using ParentType = SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, ThisType, DiffMethod::numeric, /*implicit=*/true>;
260
262 using GridView = typename GridGeometry::GridView;
263 using FVElementGeometry = typename GridGeometry::LocalView;
264 using Element = typename GridView::template Codim<0>::Entity;
266
267 static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
268 static constexpr int dim = GridView::dimension;
269
272 static constexpr auto domainI = Dune::index_constant<id>();
273
274public:
278
282 template<class ScvOrLocalDof, class ElemSol>
283 void maybeUpdateCouplingContext(const ScvOrLocalDof& scvOrLocalDof, ElemSol& elemSol, const int pvIdx)
284 {
285 this->couplingManager().updateCouplingContext(domainI, *this, domainI, scvOrLocalDof.dofIndex(), elemSol[Detail::LocalDofs::index(scvOrLocalDof)], pvIdx);
286 }
287
291 template<class JacobianMatrixDiagBlock, class GridVariables>
292 void maybeEvalAdditionalDomainDerivatives(const ElementResidualVector& origResiduals, JacobianMatrixDiagBlock& A, GridVariables& gridVariables)
293 {
294 this->couplingManager().evalAdditionalDomainDerivatives(domainI, *this, origResiduals, A, gridVariables);
295 }
296
301 template<std::size_t otherId, class JacobianBlock, class GridVariables>
302 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
303 const ElementResidualVector& res, GridVariables& gridVariables)
304 {
306 // Calculate derivatives of all dofs in the element with respect to all dofs in the coupling stencil. //
308
309 // get some aliases for convenience
310 const auto& element = this->element();
311 const auto& fvGeometry = this->fvGeometry();
312 auto&& curElemVolVars = this->curElemVolVars();
313 auto&& elemFluxVarsCache = this->elemFluxVarsCache();
314
315 // convenience lambda for call to update self
316 auto updateCoupledVariables = [&] ()
317 {
318 // Update ourself after the context has been modified. Depending on the
319 // type of caching, other objects might have to be updated. All ifs can be optimized away.
320 if constexpr (enableGridFluxVarsCache)
321 {
322 if constexpr (enableGridVolVarsCache)
323 this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), gridVariables.gridFluxVarsCache());
324 else
325 this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, gridVariables.gridFluxVarsCache());
326 }
327 else
328 {
329 if constexpr (enableGridVolVarsCache)
330 this->couplingManager().updateCoupledVariables(domainI, *this, gridVariables.curGridVolVars(), elemFluxVarsCache);
331 else
332 this->couplingManager().updateCoupledVariables(domainI, *this, curElemVolVars, elemFluxVarsCache);
333 }
334 };
335
336 // get element stencil information
337 const auto& stencil = this->couplingManager().couplingStencil(domainI, element, domainJ);
338 const auto& curSolJ = this->curSol(domainJ);
339 for (const auto globalJ : stencil)
340 {
341 // undeflected privars and privars to be deflected
342 const auto origPriVarsJ = curSolJ[globalJ];
343 auto priVarsJ = origPriVarsJ;
344
345 // the undeflected coupling residual
346 const auto origResidual = this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
347
348 for (int pvIdx = 0; pvIdx < JacobianBlock::block_type::cols; ++pvIdx)
349 {
350 auto evalCouplingResidual = [&](Scalar priVar)
351 {
352 priVarsJ[pvIdx] = priVar;
353 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx);
354 updateCoupledVariables();
355 return this->couplingManager().evalCouplingResidual(domainI, *this, domainJ, globalJ);
356 };
357
358 // derive the residuals numerically
359 ElementResidualVector partialDerivs(Detail::LocalDofs::numLocalDofs(fvGeometry));
360
361 const auto& paramGroup = this->assembler().problem(domainJ).paramGroup();
362 static const int numDiffMethod = getParamFromGroup<int>(paramGroup, "Assembly.NumericDifferenceMethod");
363 static const auto epsCoupl = this->couplingManager().numericEpsilon(domainJ, paramGroup);
364
365 NumericDifferentiation::partialDerivative(evalCouplingResidual, origPriVarsJ[pvIdx], partialDerivs, origResidual,
366 epsCoupl(origPriVarsJ[pvIdx], pvIdx), numDiffMethod);
367
368 // update the global stiffness matrix with the current partial derivatives
369 for (const auto& scv : scvs(fvGeometry))
370 {
371 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
372 {
373 // A[i][col][eqIdx][pvIdx] is the rate of change of
374 // the residual of equation 'eqIdx' at dof 'i'
375 // depending on the primary variable 'pvIdx' at dof
376 // 'col'.
377 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] += partialDerivs[scv.localDofIndex()][eqIdx];
378
379 // For the old boundary interface we set them for each scv
380 // for the new interface we enforce them globally by constraints, i.e. do nothing here
381 if constexpr (!Detail::hasProblemBoundaryTypesForIntersectionFunction<Problem, FVElementGeometry, typename GridGeometry::GridView::Intersection>())
382 {
383 // If the dof is coupled by a Dirichlet condition,
384 // set the derived value only once (i.e. overwrite existing values).
385 if (this->elemBcTypes().hasDirichlet())
386 {
387 const auto bcTypes = this->elemBcTypes().get(fvGeometry, scv);
388 if (bcTypes.isCouplingDirichlet(eqIdx))
389 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = partialDerivs[scv.localDofIndex()][eqIdx];
390 else if (bcTypes.isDirichlet(eqIdx))
391 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0;
392 }
393 }
394
395 // enforce internal Dirichlet constraints
396 if constexpr (Problem::enableInternalDirichletConstraints())
397 {
398 const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
399 if (internalDirichletConstraints[eqIdx])
400 A[scv.dofIndex()][globalJ][eqIdx][pvIdx] = 0.0;
401 }
402 }
403 }
404
405 // update the global stiffness matrix with the current partial derivatives for non-cv dofs
406 if constexpr (Detail::LocalDofs::hasNonCVLocalDofsInterface<FVElementGeometry>())
407 {
408 for (const auto& localDof : nonCVLocalDofs(fvGeometry))
409 {
410 for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
411 {
412 // A[i][col][eqIdx][pvIdx] is the rate of change of
413 // the residual of equation 'eqIdx' at dof 'i'
414 // depending on the primary variable 'pvIdx' at dof
415 // 'col'.
416 A[localDof.dofIndex()][globalJ][eqIdx][pvIdx] += partialDerivs[localDof.index()][eqIdx];
417 }
418 }
419 }
420
421 // restore the current element solution
422 priVarsJ[pvIdx] = origPriVarsJ[pvIdx];
423
424 // restore the undeflected state of the coupling context
425 this->couplingManager().updateCouplingContext(domainI, *this, domainJ, globalJ, priVarsJ, pvIdx);
426 }
427
428 // Restore original state of the flux vars cache and/or vol vars.
429 // This has to be done in case they depend on variables of domainJ before
430 // we continue with the numeric derivative w.r.t the next globalJ. Otherwise,
431 // the next "origResidual" will be incorrect.
432 updateCoupledVariables();
433 }
434 }
435};
436
443template<std::size_t id, class TypeTag, class Assembler>
444class SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>
445: public SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler,
446 SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, false>, DiffMethod::numeric, false >
447{
448 using ThisType = SubDomainCVFELocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/false>;
449 using ParentType = SubDomainCVFELocalAssemblerBase<id, TypeTag, Assembler, ThisType, DiffMethod::numeric, /*implicit=*/false>;
450
451public:
455
462 template<std::size_t otherId, class JacobianBlock, class GridVariables>
463 void assembleJacobianCoupling(Dune::index_constant<otherId> domainJ, JacobianBlock& A,
464 const ElementResidualVector& res, GridVariables& gridVariables)
465 {}
466};
467
468} // end namespace Dumux
469
470#endif
An assembler for Jacobian and residual contribution per element (CVFE methods)
An assembler for Jacobian and residual contribution per element (CVFE methods)
Definition: assembly/cvfelocalassembler.hh:317
The interface of the coupling manager for multi domain problems.
Definition: multidomain/couplingmanager.hh:37
Definition: partialreassembler.hh:32
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
CVFE scheme multi domain local assembler using numeric differentiation and explicit time discretizati...
Definition: multidomain/subdomaincvfelocalassembler.hh:447
typename ParentType::LocalResidual::ElementResidualVector ElementResidualVector
export element residual vector type
Definition: multidomain/subdomaincvfelocalassembler.hh:454
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const ElementResidualVector &res, GridVariables &gridVariables)
Computes the coupling derivatives with respect to the given element and adds them to the global matri...
Definition: multidomain/subdomaincvfelocalassembler.hh:463
CVFE scheme multi domain local assembler using numeric differentiation and implicit time discretizati...
Definition: multidomain/subdomaincvfelocalassembler.hh:256
void maybeEvalAdditionalDomainDerivatives(const ElementResidualVector &origResiduals, JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
Update the additional domain derivatives for coupled models.
Definition: multidomain/subdomaincvfelocalassembler.hh:292
typename ParentType::LocalResidual::ElementResidualVector ElementResidualVector
export element residual vector type
Definition: multidomain/subdomaincvfelocalassembler.hh:277
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacobianBlock &A, const ElementResidualVector &res, GridVariables &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix.
Definition: multidomain/subdomaincvfelocalassembler.hh:302
void maybeUpdateCouplingContext(const ScvOrLocalDof &scvOrLocalDof, ElemSol &elemSol, const int pvIdx)
Update the coupling context for coupled models.
Definition: multidomain/subdomaincvfelocalassembler.hh:283
A base class for all CVFE subdomain local assemblers.
Definition: multidomain/subdomaincvfelocalassembler.hh:53
const auto & curSol(Dune::index_constant< i > dId=domainId) const
return reference to the underlying problem
Definition: multidomain/subdomaincvfelocalassembler.hh:221
static constexpr auto domainId
export the domain id of this sub-domain
Definition: multidomain/subdomaincvfelocalassembler.hh:80
SubDomainCVFELocalAssemblerBase(const Assembler &assembler, const Element &element, const SolutionVector &curSol, CouplingManager &couplingManager)
Definition: multidomain/subdomaincvfelocalassembler.hh:87
ElementResidualVector evalLocalSourceResidual(const Element &element, const ElementVolumeVariables &elemVolVars) const
Evaluates the local source term for an element and given element volume variables.
Definition: multidomain/subdomaincvfelocalassembler.hh:152
void bindLocalViews()
Prepares all local views necessary for local assembly.
Definition: multidomain/subdomaincvfelocalassembler.hh:181
typename ParentType::LocalResidual::ElementResidualVector ElementResidualVector
export element residual vector type
Definition: multidomain/subdomaincvfelocalassembler.hh:84
ElementResidualVector evalLocalSourceResidual(const Element &neighbor) const
Evaluates the local source term depending on time discretization scheme.
Definition: multidomain/subdomaincvfelocalassembler.hh:175
const Problem & problem(Dune::index_constant< i > dId=domainId) const
return reference to the underlying problem
Definition: multidomain/subdomaincvfelocalassembler.hh:216
CouplingManager & couplingManager()
return reference to the coupling manager
Definition: multidomain/subdomaincvfelocalassembler.hh:225
void assembleJacobianCoupling(Dune::index_constant< otherId > domainJ, JacRow &jacRow, const ElementResidualVector &res, GridVariables &gridVariables)
Assemble the entries in a coupling block of the jacobian. There is no coupling block between a domain...
Definition: multidomain/subdomaincvfelocalassembler.hh:134
void assembleJacobianAndResidual(JacobianMatrixRow &jacRow, SubResidualVector &res, GridVariablesTuple &gridVariables)
Computes the derivatives with respect to the given element and adds them to the global matrix....
Definition: multidomain/subdomaincvfelocalassembler.hh:110
The CVFE scheme multidomain local assembler.
Definition: multidomain/subdomaincvfelocalassembler.hh:244
Defines all properties used in Dumux.
An enum class to define various differentiation methods available in order to compute the derivatives...
Helper classes to compute the integration elements.
DiffMethod
Differentiation methods in order to compute the derivatives of the residual i.e. the entries in the j...
Definition: diffmethod.hh:25
typename NumEqVectorTraits< PrimaryVariables >::type NumEqVector
A vector with the same size as numbers of equations This is the default implementation and has to be ...
Definition: numeqvector.hh:34
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
auto volume(const Geometry &geo, unsigned int integrationOrder=4)
The volume of a given geometry.
Definition: volume.hh:159
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: adapt.hh:17
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition: extrusion.hh:166
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition: localdof.hh:79
Definition: common/pdesolver.hh:24
A helper to deduce a vector with the same size as numbers of equations.
A class for numeric differentiation.
An adapter class for local assemblers using numeric differentiation.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
A arithmetic block vector type based on DUNE's reserved vector.