14#ifndef DUMUX_MULTIDOMAIN_FV_ASSEMBLER_HH
15#define DUMUX_MULTIDOMAIN_FV_ASSEMBLER_HH
20#include <dune/common/hybridutilities.hh>
21#include <dune/istl/matrixindexset.hh>
42#if HAVE_DUMUX_OLD_STAGGERED
43#include <dumux/multidomain/subdomainstaggeredlocalassembler.hh>
48template<std::
size_t id,
class TypeTag,
class Assembler, DiffMethod DM,
bool implicit>
51namespace Grid::Capabilities {
55template<
class T, std::size_t... I>
79{
return Dune::Std::is_detected<SubProblemConstraintsDetector, P>::value; }
89struct CouplingManagerSupportsMultithreadedAssembly :
public std::false_type
101template<
class MDTraits,
class CMType, DiffMethod diffMethod,
bool useImplicitAssembly = true>
104 template<std::
size_t id>
105 using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
110 using Scalar =
typename MDTraits::Scalar;
112 template<std::
size_t id>
113 using LocalResidual =
typename MDTraits::template SubDomain<id>::LocalResidual;
115 template<std::
size_t id>
116 using GridVariables =
typename MDTraits::template SubDomain<id>::GridVariables;
118 template<std::
size_t id>
119 using GridGeometry =
typename MDTraits::template SubDomain<id>::GridGeometry;
121 template<std::
size_t id>
122 using Problem =
typename MDTraits::template SubDomain<id>::Problem;
134 {
return useImplicitAssembly; }
138 using ProblemTuple =
typename MDTraits::template TupleOfSharedPtrConst<Problem>;
139 using GridGeometryTuple =
typename MDTraits::template TupleOfSharedPtrConst<GridGeometry>;
140 using GridVariablesTuple =
typename MDTraits::template TupleOfSharedPtr<GridVariables>;
145 template<std::
size_t id>
148 template<
class DiscretizationMethod, std::
size_t id>
149 struct SubDomainAssemblerType;
151 template<std::
size_t id>
152 struct SubDomainAssemblerType<DiscretizationMethods::CCTpfa, id>
157 template<std::
size_t id>
158 struct SubDomainAssemblerType<DiscretizationMethods::CCMpfa, id>
160 using type = SubDomainCCLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
163 template<std::
size_t id,
class DM>
164 struct SubDomainAssemblerType<DiscretizationMethods::CVFE<DM>, id>
166 using type = SubDomainCVFELocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
169 template<std::
size_t id>
170 struct SubDomainAssemblerType<DiscretizationMethods::Staggered, id>
172 using type = SubDomainStaggeredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
175 template<std::
size_t id>
176 struct SubDomainAssemblerType<DiscretizationMethods::FCStaggered, id>
178 using type = SubDomainFaceCenteredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
181 template<std::
size_t id>
182 using SubDomainAssembler =
typename SubDomainAssemblerType<typename GridGeometry<id>::DiscretizationMethod,
id>::type;
197 , problemTuple_(std::move(
problem))
201 , isStationaryProblem_(true)
202 , warningIssued_(false)
204 static_assert(
isImplicit(),
"Explicit assembler for stationary problem doesn't make sense!");
205 std::cout <<
"Instantiated assembler for a stationary problem." << std::endl;
210 && getParam<bool>(
"Assembly.Multithreading",
true);
212 maybeComputeColors_();
224 std::shared_ptr<const TimeLoop> timeLoop,
227 , problemTuple_(std::move(
problem))
230 , timeLoop_(timeLoop)
232 , isStationaryProblem_(false)
233 , warningIssued_(false)
235 std::cout <<
"Instantiated assembler for an instationary problem." << std::endl;
240 && getParam<bool>(
"Assembly.Multithreading",
true);
242 maybeComputeColors_();
251 checkAssemblerState_();
255 using namespace Dune::Hybrid;
256 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainId)
258 auto& jacRow = (*jacobian_)[domainId];
259 auto& subRes = (*residual_)[domainId];
260 const auto& subSol = curSol[domainId];
261 this->assembleJacobianAndResidual_(domainId, jacRow, subRes, curSol);
263 const auto gridGeometry = std::get<domainId>(gridGeometryTuple_);
264 enforcePeriodicConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
265 enforceGlobalDirichletConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
281 checkAssemblerState_();
286 using namespace Dune::Hybrid;
287 forEach(integralRange(Dune::Hybrid::size(r)), [&](
const auto domainId)
289 auto& subRes = r[domainId];
290 this->assembleResidual_(domainId, subRes, curSol);
300 std::shared_ptr<ResidualType> r)
306 setJacobianPattern_(*jacobian_);
307 setResidualSize_(*residual_);
316 jacobian_ = std::make_shared<JacobianMatrix>();
317 residual_ = std::make_shared<ResidualType>();
320 setJacobianPattern_(*jacobian_);
321 setResidualSize_(*residual_);
329 using namespace Dune::Hybrid;
330 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto i)
332 forEach(jac[i], [&](
auto& jacBlock)
334 using BlockType = std::decay_t<
decltype(jacBlock)>;
335 if (jacBlock.buildMode() == BlockType::BuildMode::unknown)
336 jacBlock.setBuildMode(BlockType::BuildMode::random);
337 else if (jacBlock.buildMode() != BlockType::BuildMode::random)
338 DUNE_THROW(Dune::NotImplemented,
"Only BCRS matrices with random build mode are supported at the moment");
348 setJacobianPattern_(*jacobian_);
349 setResidualSize_(*residual_);
350 maybeComputeColors_();
358 using namespace Dune::Hybrid;
359 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
360 { this->
gridVariables(domainId).update(curSol[domainId]); });
368 using namespace Dune::Hybrid;
369 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
370 { this->
gridVariables(domainId).resetTimeStep(curSol[domainId]); });
374 template<std::
size_t i>
375 std::size_t
numDofs(Dune::index_constant<i> domainId)
const
376 {
return std::get<domainId>(gridGeometryTuple_)->numDofs(); }
379 template<std::
size_t i>
380 const auto&
problem(Dune::index_constant<i> domainId)
const
381 {
return *std::get<domainId>(problemTuple_); }
384 template<std::
size_t i>
386 {
return *std::get<domainId>(gridGeometryTuple_); }
389 template<std::
size_t i>
390 const auto&
gridView(Dune::index_constant<i> domainId)
const
394 template<std::
size_t i>
396 {
return *std::get<domainId>(gridVariablesTuple_); }
399 template<std::
size_t i>
401 {
return *std::get<domainId>(gridVariablesTuple_); }
409 {
return *jacobian_; }
413 {
return *residual_; }
417 {
return *prevSol_; }
424 { timeLoop_ = timeLoop; isStationaryProblem_ = !(
static_cast<bool>(timeLoop)); }
437 {
return isStationaryProblem_; }
442 template<std::
size_t i>
444 {
return LocalResidual<i>(std::get<domainId>(problemTuple_).get(), timeLoop_.get()); }
456 using namespace Dune::Hybrid;
457 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainI)
459 forEach(integralRange(Dune::Hybrid::size(jac[domainI])), [&](
const auto domainJ)
461 const auto pattern = this->getJacobianPattern_(domainI, domainJ);
462 pattern.exportIdx(jac[domainI][domainJ]);
472 using namespace Dune::Hybrid;
473 forEach(integralRange(Dune::Hybrid::size(res)), [&](
const auto domainId)
474 { res[domainId].resize(this->
numDofs(domainId)); });
478 void resetResidual_()
482 residual_ = std::make_shared<ResidualType>();
483 setResidualSize_(*residual_);
490 void resetJacobian_()
494 jacobian_ = std::make_shared<JacobianMatrix>();
496 setJacobianPattern_(*jacobian_);
503 void maybeComputeColors_()
505 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
506 if (enableMultithreading_)
511 void checkAssemblerState_()
const
513 if (!isStationaryProblem_ && !prevSol_)
514 DUNE_THROW(Dune::InvalidStateException,
"Assembling instationary problem but previous solution was not set!");
516 if (isStationaryProblem_ && prevSol_)
517 DUNE_THROW(Dune::InvalidStateException,
"Assembling stationary problem but a previous solution was set."
518 <<
" Did you forget to set the timeLoop to make this problem instationary?");
521 template<std::
size_t i,
class JacRow,
class SubRes>
522 void assembleJacobianAndResidual_(Dune::index_constant<i> domainId, JacRow& jacRow, SubRes& subRes,
525 assemble_(domainId, [&](
const auto& element)
527 MultiDomainAssemblerSubDomainView view{*
this, domainId};
528 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
529 subDomainAssembler.assembleJacobianAndResidual(jacRow, subRes, gridVariablesTuple_);
533 template<std::
size_t i,
class SubRes>
534 void assembleResidual_(Dune::index_constant<i> domainId, SubRes& subRes,
537 assemble_(domainId, [&](
const auto& element)
539 MultiDomainAssemblerSubDomainView view{*
this, domainId};
540 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
541 subDomainAssembler.assembleResidual(subRes);
550 template<std::
size_t i,
class AssembleElementFunc>
551 void assemble_(Dune::index_constant<i> domainId, AssembleElementFunc&& assembleElement)
const
554 bool succeeded =
false;
559 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
561 if (enableMultithreading_)
564 domainId, std::forward<AssembleElementFunc>(assembleElement)
573 for (
const auto& element : elements(
gridView(domainId)))
574 assembleElement(element);
580 catch (NumericalProblem &e)
582 std::cout <<
"rank " <<
gridView(domainId).comm().rank()
583 <<
" caught an exception while assembling:" << e.what()
589 if (
gridView(domainId).comm().size() > 1)
590 succeeded =
gridView(domainId).comm().min(succeeded);
594 DUNE_THROW(NumericalProblem,
"A process did not succeed in linearizing the system");
598 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i==j),
int> = 0>
599 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
600 Dune::index_constant<j> domainJ)
const
603 auto pattern = getJacobianPattern<isImplicit()>(gg);
609 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i!=j),
int> = 0>
610 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
611 Dune::index_constant<j> domainJ)
const
619 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
620 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
622 if constexpr (Detail::hasPeriodicDofMap<GG>())
626 if (m.first < m.second)
628 auto& jac = jacRow[domainI];
631 res[m.first] += res[m.second];
633 const auto end = jac[m.second].end();
634 for (
auto it = jac[m.second].begin(); it != end; ++it)
635 jac[m.first][it.index()] += (*it);
639 res[m.second] = curSol[m.second] - curSol[m.first];
642 auto setMatrixBlock = [] (
auto& matrixBlock,
double diagValue)
644 for (
int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
645 matrixBlock[eIdx][eIdx] = diagValue;
648 for (
auto it = jac[m.second].begin(); it != end; ++it)
650 auto& matrixBlock = *it;
653 assert(matrixBlock.N() == matrixBlock.M());
654 if(it.index() == m.second)
655 setMatrixBlock(matrixBlock, 1.0);
657 if(it.index() == m.first)
658 setMatrixBlock(matrixBlock, -1.0);
662 using namespace Dune::Hybrid;
665 auto& jacCoupling = jacRow[couplingDomainId];
667 for (
auto it = jacCoupling[m.second].begin(); it != jacCoupling[m.second].end(); ++it)
668 jacCoupling[m.first][it.index()] += (*it);
670 for (
auto it = jacCoupling[m.second].begin(); it != jacCoupling[m.second].end(); ++it)
679 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
680 void enforceGlobalDirichletConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
682 if constexpr (Detail::hasSubProblemGlobalConstraints<Problem<domainI>>())
684 auto& jac = jacRow[domainI];
685 auto applyDirichletConstraint = [&] (
const auto& dofIdx,
690 (res)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
692 auto& row = jac[dofIdx];
693 for (
auto col = row.begin(); col != row.end(); ++col)
694 row[col.index()][eqIdx] = 0.0;
696 jac[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
698 using namespace Dune::Hybrid;
701 auto& jacCoupling = jacRow[couplingDomainId];
703 auto& rowCoupling = jacCoupling[dofIdx];
704 for (
auto colCoupling = rowCoupling.begin(); colCoupling != rowCoupling.end(); ++colCoupling)
705 rowCoupling[colCoupling.index()][eqIdx] = 0.0;
710 for (
const auto& constraintData : this->
problem(domainI).constraints())
712 const auto& constraintInfo = constraintData.constraintInfo();
713 const auto& values = constraintData.values();
714 const auto dofIdx = constraintData.dofIndex();
716 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
718 if (constraintInfo.isConstraintEquation(eqIdx))
720 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
721 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
722 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
730 ProblemTuple problemTuple_;
733 GridGeometryTuple gridGeometryTuple_;
736 GridVariablesTuple gridVariablesTuple_;
739 std::shared_ptr<const TimeLoop> timeLoop_;
745 bool isStationaryProblem_;
748 std::shared_ptr<JacobianMatrix> jacobian_;
749 std::shared_ptr<ResidualType> residual_;
752 mutable bool warningIssued_;
755 bool enableMultithreading_ =
false;
Subdomain-specific views on multidomain assemblers.
Subdomain-specific view on a multidomain assembler. Allows retrieval of sub-domain specific objects w...
Definition: assemblerview.hh:31
A linear system assembler (residual and Jacobian) for finite volume schemes (box, tpfa,...
Definition: multidomain/fvassembler.hh:103
std::size_t numDofs(Dune::index_constant< i > domainId) const
the number of dof locations of domain i
Definition: multidomain/fvassembler.hh:375
void updateGridVariables(const SolutionVector &curSol)
Updates the grid variables with the given solution.
Definition: multidomain/fvassembler.hh:356
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition: multidomain/fvassembler.hh:346
typename MDTraits::SolutionVector SolutionVector
Definition: multidomain/fvassembler.hh:125
typename MDTraits::template SubDomain< id >::Problem Problem
Definition: multidomain/fvassembler.hh:122
JacobianMatrix & jacobian()
the full Jacobian matrix
Definition: multidomain/fvassembler.hh:408
static constexpr bool isImplicit()
Returns true if the assembler considers implicit assembly.
Definition: multidomain/fvassembler.hh:133
void assembleResidual(ResidualType &r, const SolutionVector &curSol)
assemble a residual r
Definition: multidomain/fvassembler.hh:277
typename MDTraits::JacobianMatrix JacobianMatrix
Definition: multidomain/fvassembler.hh:124
CMType CouplingManager
Definition: multidomain/fvassembler.hh:128
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition: multidomain/fvassembler.hh:270
void resetTimeStep(const SolutionVector &curSol)
Resets the grid variables to the last time step.
Definition: multidomain/fvassembler.hh:366
const GridVariables< i > & gridVariables(Dune::index_constant< i > domainId) const
the grid variables of domain i
Definition: multidomain/fvassembler.hh:400
void setPreviousSolution(const SolutionVector &u)
Sets the solution from which to start the time integration. Has to be called prior to assembly for ti...
Definition: multidomain/fvassembler.hh:430
typename MDTraits::template SubDomain< id >::GridVariables GridVariables
Definition: multidomain/fvassembler.hh:116
const auto & gridGeometry(Dune::index_constant< i > domainId) const
the finite volume grid geometry of domain i
Definition: multidomain/fvassembler.hh:385
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition: multidomain/fvassembler.hh:314
const auto & gridView(Dune::index_constant< i > domainId) const
the grid view of domain i
Definition: multidomain/fvassembler.hh:390
typename MDTraits::template SubDomain< id >::GridGeometry GridGeometry
Definition: multidomain/fvassembler.hh:119
const CouplingManager & couplingManager() const
the coupling manager
Definition: multidomain/fvassembler.hh:404
void setTimeManager(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition: multidomain/fvassembler.hh:423
const SolutionVector & prevSol() const
the solution of the previous time step
Definition: multidomain/fvassembler.hh:416
GridVariables< i > & gridVariables(Dune::index_constant< i > domainId)
the grid variables of domain i
Definition: multidomain/fvassembler.hh:395
std::shared_ptr< CouplingManager > couplingManager_
the coupling manager coupling the sub domains
Definition: multidomain/fvassembler.hh:448
MDTraits Traits
Definition: multidomain/fvassembler.hh:108
MultiDomainFVAssembler(ProblemTuple problem, GridGeometryTuple gridGeometry, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager, std::shared_ptr< const TimeLoop > timeLoop, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition: multidomain/fvassembler.hh:220
void setJacobianBuildMode(JacobianMatrix &jac) const
Sets the jacobian build mode.
Definition: multidomain/fvassembler.hh:327
typename MDTraits::template SubDomain< id >::LocalResidual LocalResidual
Definition: multidomain/fvassembler.hh:113
LocalResidual< i > localResidual(Dune::index_constant< i > domainId) const
Create a local residual object (used by the local assembler)
Definition: multidomain/fvassembler.hh:443
const auto & problem(Dune::index_constant< i > domainId) const
the problem of domain i
Definition: multidomain/fvassembler.hh:380
typename MDTraits::ResidualVector ResidualType
Definition: multidomain/fvassembler.hh:126
MultiDomainFVAssembler(ProblemTuple problem, GridGeometryTuple gridGeometry, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager)
The constructor for stationary problems.
Definition: multidomain/fvassembler.hh:192
void assembleJacobianAndResidual(const SolutionVector &curSol)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition: multidomain/fvassembler.hh:249
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition: multidomain/fvassembler.hh:436
typename MDTraits::Scalar Scalar
Definition: multidomain/fvassembler.hh:110
ResidualType & residual()
the full residual vector
Definition: multidomain/fvassembler.hh:412
void setLinearSystem(std::shared_ptr< JacobianMatrix > A, std::shared_ptr< ResidualType > r)
Tells the assembler which jacobian and residual to use. This also resizes the containers to the requi...
Definition: multidomain/fvassembler.hh:299
The cell-centered scheme multidomain local assembler.
Definition: multidomain/subdomaincclocalassembler.hh:270
Definition: multidomain/fvassembler.hh:49
The default time loop for instationary simulations.
Definition: common/timeloop.hh:139
Defines all properties used in Dumux.
Manages the handling of time dependent problems.
Helper function to generate Jacobian pattern for multi domain models.
An enum class to define various differentiation methods available in order to compute the derivatives...
Some exceptions thrown in DuMux
dune-grid capabilities compatibility layer
constexpr bool isSerial()
Checking whether the backend is serial.
Definition: multithreading.hh:45
Helper function to generate Jacobian pattern for different discretization methods.
The available discretization methods in Dumux.
A multidomain local assembler for Jacobian and residual contribution per element (cell-centered metho...
An assembler for Jacobian and residual contribution per element (CVFE methods) for multidomain proble...
decltype(std::declval< P >().constraints()) SubProblemConstraintsDetector
helper struct detecting if sub-problem has a constraints() function
Definition: multidomain/fvassembler.hh:75
constexpr bool hasSubProblemGlobalConstraints()
Definition: multidomain/fvassembler.hh:78
bool allGridsSupportsMultithreadingImpl(const T &gridGeometries, std::index_sequence< I... >)
Definition: multistagemultidomainfvassembler.hh:52
bool allGridsSupportsMultithreading(const std::tuple< GG... > &gridGeometries)
Definition: multistagemultidomainfvassembler.hh:60
bool supportsMultithreading(const GridView &gridView)
Definition: gridcapabilities.hh:34
typename Detail::ConcatSeq< decltype(std::make_index_sequence< e >{}), e+1, decltype(std::make_index_sequence<(n > e) ?(n - e - 1) :0 >{})>::type makeIncompleteIntegerSequence
Definition: utility.hh:59
Provides a helper class for nonoverlapping decomposition.
Type traits to detect periodicity support.
Type trait that is specialized for coupling manager supporting multithreaded assembly.
Definition: multistagemultidomainfvassembler.hh:78
An assembler for Jacobian and residual contribution per element (face-centered staggered methods) for...
Utilities for template meta programming.