14#ifndef DUMUX_MULTIDOMAIN_ASSEMBLER_HH
15#define DUMUX_MULTIDOMAIN_ASSEMBLER_HH
23#include <dune/common/hybridutilities.hh>
24#include <dune/istl/matrixindexset.hh>
34#include <dumux/common/concepts/variables_.hh>
42#include "subdomaincvfelocalassembler_.hh"
49#if HAVE_DUMUX_OLD_STAGGERED
50#include <dumux/multidomain/subdomainstaggeredlocalassembler.hh>
64template<
class MDTraits,
class CMType, DiffMethod diffMethod,
bool useImplicitAssembly = true>
67 template<std::
size_t id>
68 using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
73 using Scalar =
typename MDTraits::Scalar;
75 template<std::
size_t id>
76 using LocalResidual =
typename MDTraits::template SubDomain<id>::LocalResidual;
78 template<std::
size_t id>
79 using GridVariables =
typename MDTraits::template SubDomain<id>::GridVariables;
81 template<std::
size_t id>
84 template<std::
size_t id>
85 using Problem =
typename MDTraits::template SubDomain<id>::Problem;
97 {
return useImplicitAssembly; }
101 using ProblemTuple =
typename MDTraits::template TupleOfSharedPtrConst<Problem>;
102 using GridDiscretizationTuple =
typename MDTraits::template TupleOfSharedPtrConst<GridDiscretization>;
103 using GridVariablesTuple =
typename MDTraits::template TupleOfSharedPtr<GridVariables>;
108 template<std::
size_t id>
111 template<
class DiscretizationMethod, std::
size_t id>
112 struct SubDomainAssemblerType;
114 template<std::
size_t id>
120 template<std::
size_t id>
126 template<std::
size_t id,
class DM>
127 struct SubDomainAssemblerType<DiscretizationMethods::CVFE<DM>, id>
131 static constexpr bool usesGeneralGridVariables =
132 Dumux::Concept::GridVariables<GV> && !Dumux::Concept::FVGridVariables<GV>;
134 using type = std::conditional_t<usesGeneralGridVariables,
139#if HAVE_DUMUX_OLD_STAGGERED
140 template<std::
size_t id>
141 struct SubDomainAssemblerType<DiscretizationMethods::Staggered, id>
143 using type = SubDomainStaggeredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
147 template<std::
size_t id>
148 struct SubDomainAssemblerType<DiscretizationMethods::FCStaggered, id>
150 using type = SubDomainFaceCenteredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
153 template<std::
size_t id>
154 using SubDomainAssembler =
typename SubDomainAssemblerType<typename GridDiscretization<id>::DiscretizationMethod,
id>::type;
168 , problemTuple_(std::move(
problem))
172 , isStationaryProblem_(true)
173 , warningIssued_(false)
175 static_assert(
isImplicit(),
"Explicit assembler for stationary problem doesn't make sense!");
176 std::cout <<
"Instantiated assembler for a stationary problem." << std::endl;
183 maybeComputeColors_();
195 std::shared_ptr<const TimeLoop> timeLoop,
198 , problemTuple_(std::move(
problem))
201 , timeLoop_(timeLoop)
203 , isStationaryProblem_(false)
204 , warningIssued_(false)
206 std::cout <<
"Instantiated assembler for an instationary problem." << std::endl;
213 maybeComputeColors_();
222 checkAssemblerState_();
226 using namespace Dune::Hybrid;
227 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainId)
229 auto& jacRow = (*jacobian_)[domainId];
230 auto& subRes = (*residual_)[domainId];
231 const auto& subSol = curSol[domainId];
232 this->assembleJacobianAndResidual_(domainId, jacRow, subRes, curSol);
252 checkAssemblerState_();
257 using namespace Dune::Hybrid;
258 forEach(integralRange(Dune::Hybrid::size(r)), [&](
const auto domainId)
260 auto& subRes = r[domainId];
261 const auto& subSol = curSol[domainId];
262 this->assembleResidual_(domainId, subRes, curSol);
276 std::shared_ptr<ResidualType> r)
282 setJacobianPattern_(*jacobian_);
283 setResidualSize_(*residual_);
292 jacobian_ = std::make_shared<JacobianMatrix>();
293 residual_ = std::make_shared<ResidualType>();
296 setJacobianPattern_(*jacobian_);
297 setResidualSize_(*residual_);
305 using namespace Dune::Hybrid;
306 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto i)
308 forEach(jac[i], [&](
auto& jacBlock)
310 using BlockType = std::decay_t<
decltype(jacBlock)>;
311 if (jacBlock.buildMode() == BlockType::BuildMode::unknown)
312 jacBlock.setBuildMode(BlockType::BuildMode::random);
313 else if (jacBlock.buildMode() != BlockType::BuildMode::random)
314 DUNE_THROW(Dune::NotImplemented,
"Only BCRS matrices with random build mode are supported at the moment");
324 setJacobianPattern_(*jacobian_);
325 setResidualSize_(*residual_);
326 maybeComputeColors_();
334 using namespace Dune::Hybrid;
335 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
336 { this->
gridVariables(domainId).update(curSol[domainId]); });
344 using namespace Dune::Hybrid;
345 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
346 { this->
gridVariables(domainId).resetTimeStep(curSol[domainId]); });
350 template<std::
size_t i>
351 std::size_t
numDofs(Dune::index_constant<i> domainId)
const
352 {
return std::get<domainId>(gridDiscretizationTuple_)->numDofs(); }
355 template<std::
size_t i>
356 const auto&
problem(Dune::index_constant<i> domainId)
const
357 {
return *std::get<domainId>(problemTuple_); }
360 template<std::
size_t i>
362 {
return *std::get<domainId>(gridDiscretizationTuple_); }
365 template<std::
size_t i>
366 const auto&
gridView(Dune::index_constant<i> domainId)
const
370 template<std::
size_t i>
372 {
return *std::get<domainId>(gridVariablesTuple_); }
375 template<std::
size_t i>
377 {
return *std::get<domainId>(gridVariablesTuple_); }
385 {
return *jacobian_; }
389 {
return *residual_; }
393 {
return *prevSol_; }
400 { timeLoop_ = timeLoop; isStationaryProblem_ = !(
static_cast<bool>(timeLoop)); }
413 {
return isStationaryProblem_; }
418 template<std::
size_t i>
420 {
return LocalResidual<i>(std::get<domainId>(problemTuple_).get(), timeLoop_.get()); }
432 using namespace Dune::Hybrid;
433 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainI)
435 forEach(integralRange(Dune::Hybrid::size(jac[domainI])), [&](
const auto domainJ)
437 const auto pattern = this->getJacobianPattern_(domainI, domainJ);
438 pattern.exportIdx(jac[domainI][domainJ]);
448 using namespace Dune::Hybrid;
449 forEach(integralRange(Dune::Hybrid::size(res)), [&](
const auto domainId)
450 { res[domainId].resize(this->
numDofs(domainId)); });
454 void resetResidual_()
458 residual_ = std::make_shared<ResidualType>();
459 setResidualSize_(*residual_);
466 void resetJacobian_()
470 jacobian_ = std::make_shared<JacobianMatrix>();
472 setJacobianPattern_(*jacobian_);
479 void maybeComputeColors_()
481 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
482 if (enableMultithreading_)
487 void checkAssemblerState_()
const
489 if (!isStationaryProblem_ && !prevSol_)
490 DUNE_THROW(Dune::InvalidStateException,
"Assembling instationary problem but previous solution was not set!");
492 if (isStationaryProblem_ && prevSol_)
493 DUNE_THROW(Dune::InvalidStateException,
"Assembling stationary problem but a previous solution was set."
494 <<
" Did you forget to set the timeLoop to make this problem instationary?");
497 template<std::
size_t i,
class JacRow,
class SubRes>
498 void assembleJacobianAndResidual_(Dune::index_constant<i> domainId, JacRow& jacRow, SubRes& subRes,
501 assemble_(domainId, [&](
const auto& element)
503 MultiDomainAssemblerSubDomainView view{*
this, domainId};
504 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
505 subDomainAssembler.assembleJacobianAndResidual(jacRow, subRes, gridVariablesTuple_);
509 template<std::
size_t i,
class SubRes>
510 void assembleResidual_(Dune::index_constant<i> domainId, SubRes& subRes,
513 assemble_(domainId, [&](
const auto& element)
515 MultiDomainAssemblerSubDomainView view{*
this, domainId};
516 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
517 subDomainAssembler.assembleResidual(subRes);
526 template<std::
size_t i,
class AssembleElementFunc>
527 void assemble_(Dune::index_constant<i> domainId, AssembleElementFunc&& assembleElement)
const
530 bool succeeded =
false;
535 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
537 if (enableMultithreading_)
540 domainId, std::forward<AssembleElementFunc>(assembleElement)
549 for (
const auto& element : elements(
gridView(domainId)))
550 assembleElement(element);
556 catch (NumericalProblem &e)
558 std::cout <<
"rank " <<
gridView(domainId).comm().rank()
559 <<
" caught an exception while assembling:" << e.what()
565 if (
gridView(domainId).comm().size() > 1)
566 succeeded =
gridView(domainId).comm().min(succeeded);
570 DUNE_THROW(NumericalProblem,
"A process did not succeed in linearizing the system");
574 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i==j),
int> = 0>
575 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
576 Dune::index_constant<j> domainJ)
const
585 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i!=j),
int> = 0>
586 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
587 Dune::index_constant<j> domainJ)
const
595 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
596 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridDiscretization,
const Sol& curSol)
const
602 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
603 if (std::ranges::all_of(periodicallyMappedDofs, [&](
auto second){
return m.first < second; }))
605 for (
const auto& second : periodicallyMappedDofs)
607 auto& jac = jacRow[domainI];
610 res[m.first] += res[second];
612 const auto end = jac[second].end();
613 for (
auto it = jac[second].begin(); it != end; ++it)
614 jac[m.first][it.index()] += (*it);
618 res[second] = curSol[second] - curSol[m.first];
621 auto setMatrixBlock = [] (
auto& matrixBlock,
double diagValue)
623 for (
int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
624 matrixBlock[eIdx][eIdx] = diagValue;
627 for (
auto it = jac[second].begin(); it != end; ++it)
629 auto& matrixBlock = *it;
632 assert(matrixBlock.N() == matrixBlock.M());
633 if(it.index() == second)
634 setMatrixBlock(matrixBlock, 1.0);
636 if(it.index() == m.first)
637 setMatrixBlock(matrixBlock, -1.0);
641 using namespace Dune::Hybrid;
644 auto& jacCoupling = jacRow[couplingDomainId];
646 for (
auto it = jacCoupling[second].begin(); it != jacCoupling[second].end(); ++it)
647 jacCoupling[m.first][it.index()] += (*it);
649 for (
auto it = jacCoupling[second].begin(); it != jacCoupling[second].end(); ++it)
659 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
660 void enforceProblemConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridDiscretization,
const Sol& curSol)
const
664 auto& jac = jacRow[domainI];
665 auto applyDirichletConstraint = [&] (
const auto& dofIdx,
670 (res)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
672 auto& row = jac[dofIdx];
673 for (
auto col = row.begin(); col != row.end(); ++col)
674 row[col.index()][eqIdx] = 0.0;
676 jac[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
678 using namespace Dune::Hybrid;
681 auto& jacCoupling = jacRow[couplingDomainId];
683 auto& rowCoupling = jacCoupling[dofIdx];
684 for (
auto colCoupling = rowCoupling.begin(); colCoupling != rowCoupling.end(); ++colCoupling)
685 rowCoupling[colCoupling.index()][eqIdx] = 0.0;
690 for (
const auto& constraintData : this->
problem(domainI).constraints())
692 const auto& constraintInfo = constraintData.constraintInfo();
693 const auto& values = constraintData.values();
694 const auto dofIdx = constraintData.dofIndex();
696 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
698 if (constraintInfo.isConstraintEquation(eqIdx))
700 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
701 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
702 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
710 template<std::
size_t i,
class Res,
class GG,
class Sol>
711 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridDiscretization,
const Sol& curSol)
const
717 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
718 if (std::ranges::all_of(periodicallyMappedDofs, [&](
auto second){
return m.first < second; }))
720 for (
const auto& second : periodicallyMappedDofs)
723 res[m.first] += res[second];
726 res[second] = curSol[second] - curSol[m.first];
734 template<std::
size_t i,
class Res,
class GG,
class Sol>
735 void enforceProblemConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridDiscretization,
const Sol& curSol)
const
739 for (
const auto& constraintData : this->
problem(domainI).constraints())
741 const auto& constraintInfo = constraintData.constraintInfo();
742 const auto& values = constraintData.values();
743 const auto dofIdx = constraintData.dofIndex();
744 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
746 if (constraintInfo.isConstraintEquation(eqIdx))
748 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
749 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
750 res[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
758 ProblemTuple problemTuple_;
761 GridDiscretizationTuple gridDiscretizationTuple_;
764 GridVariablesTuple gridVariablesTuple_;
767 std::shared_ptr<const TimeLoop> timeLoop_;
773 bool isStationaryProblem_;
776 std::shared_ptr<JacobianMatrix> jacobian_;
777 std::shared_ptr<ResidualType> residual_;
780 mutable bool warningIssued_;
783 bool enableMultithreading_ =
false;
Subdomain-specific views on multidomain assemblers.
Traits shared by the multi-domain assemblers.
The interface of the coupling manager for multi domain problems.
Definition multidomain/couplingmanager.hh:37
A linear system assembler (residual and Jacobian) for general schemes (FV, CVFE, FE,...
Definition multidomain/assembler.hh:66
typename MDTraits::ResidualVector ResidualType
Definition multidomain/assembler.hh:89
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition multidomain/assembler.hh:412
typename MDTraits::template SubDomain< id >::GridVariables GridVariables
Definition multidomain/assembler.hh:79
void setJacobianBuildMode(JacobianMatrix &jac) const
Sets the jacobian build mode.
Definition multidomain/assembler.hh:303
LocalResidual< i > localResidual(Dune::index_constant< i > domainId) const
Create a local residual object (used by the local assembler).
Definition multidomain/assembler.hh:419
GetPropType< SubDomainTypeTag< id >, Properties::GridGeometry > GridDiscretization
Definition multidomain/assembler.hh:82
void updateGridVariables(const SolutionVector &curSol)
Updates the grid variables with the given solution.
Definition multidomain/assembler.hh:332
ResidualType & residual()
the full residual vector
Definition multidomain/assembler.hh:388
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition multidomain/assembler.hh:322
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/assembler.hh:275
const GridVariables< i > & gridVariables(Dune::index_constant< i > domainId) const
the grid variables of domain i
Definition multidomain/assembler.hh:376
std::size_t numDofs(Dune::index_constant< i > domainId) const
the number of dof locations of domain i
Definition multidomain/assembler.hh:351
void setTimeManager(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition multidomain/assembler.hh:399
const auto & gridView(Dune::index_constant< i > domainId) const
the grid view of domain i
Definition multidomain/assembler.hh:366
void assembleResidual(ResidualType &r, const SolutionVector &curSol)
assemble a residual r
Definition multidomain/assembler.hh:248
typename MDTraits::SolutionVector SolutionVector
Definition multidomain/assembler.hh:88
std::shared_ptr< CouplingManager > couplingManager_
Definition multidomain/assembler.hh:424
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/assembler.hh:406
JacobianMatrix & jacobian()
the full Jacobian matrix
Definition multidomain/assembler.hh:384
typename MDTraits::Scalar Scalar
Definition multidomain/assembler.hh:73
const auto & gridDiscretization(Dune::index_constant< i > domainId) const
Definition multidomain/assembler.hh:361
MDTraits Traits
Definition multidomain/assembler.hh:71
typename MDTraits::JacobianMatrix JacobianMatrix
Definition multidomain/assembler.hh:87
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition multidomain/assembler.hh:290
GridVariables< i > & gridVariables(Dune::index_constant< i > domainId)
Definition multidomain/assembler.hh:371
static constexpr bool isImplicit()
Returns true if the assembler considers implicit assembly.
Definition multidomain/assembler.hh:96
const SolutionVector & prevSol() const
Definition multidomain/assembler.hh:392
typename MDTraits::template SubDomain< id >::LocalResidual LocalResidual
Definition multidomain/assembler.hh:76
MultiDomainAssembler(ProblemTuple problem, GridDiscretizationTuple gridDiscretization, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager)
The constructor for stationary problems.
Definition multidomain/assembler.hh:163
CMType CouplingManager
Definition multidomain/assembler.hh:91
void resetTimeStep(const SolutionVector &curSol)
Resets the grid variables to the last time step.
Definition multidomain/assembler.hh:342
const auto & problem(Dune::index_constant< i > domainId) const
Definition multidomain/assembler.hh:356
const CouplingManager & couplingManager() const
Definition multidomain/assembler.hh:380
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition multidomain/assembler.hh:241
typename MDTraits::template SubDomain< id >::Problem Problem
Definition multidomain/assembler.hh:85
MultiDomainAssembler(ProblemTuple problem, GridDiscretizationTuple gridDiscretization, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager, std::shared_ptr< const TimeLoop > timeLoop, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition multidomain/assembler.hh:191
void assembleJacobianAndResidual(const SolutionVector &curSol)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition multidomain/assembler.hh:220
The cell-centered scheme multidomain local assembler.
Definition experimental/assembly/subdomaincclocalassembler.hh:195
The CVFE scheme multidomain local assembler.
Definition experimental/assembly/subdomaincvfelocalassembler.hh:207
Subdomain-specific view on a multidomain assembler. Allows retrieval of sub-domain specific objects w...
Definition assemblerview.hh:33
The cell-centered scheme multidomain local assembler.
Definition multidomain/subdomaincclocalassembler.hh:270
The CVFE scheme multidomain local assembler.
Definition multidomain/subdomaincvfelocalassembler.hh:244
Manages the handling of time dependent problems.
Definition common/timeloop.hh:84
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
Dune::MatrixIndexSet getJacobianPattern(const GridGeometry &gridGeometry)
Helper function to generate Jacobian pattern for cell-centered methods.
Definition jacobianpattern.hh:29
Dune::MatrixIndexSet getCouplingJacobianPattern(const CouplingManager &couplingManager, Dune::index_constant< i > domainI, const GridGeometryI &gridGeometryI, Dune::index_constant< j > domainJ, const GridGeometryJ &gridGeometryJ)
Helper function to generate coupling Jacobian pattern (off-diagonal blocks) for cell-centered schemes...
Definition couplingjacobianpattern.hh:33
constexpr bool isSerial()
Checking whether the backend is serial.
Definition multithreading.hh:45
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition parameters.hh:155
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition propertysystem.hh:296
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...
Definition cellcentered/mpfa/elementvolumevariables.hh:24
constexpr bool hasPeriodicDofMap()
Definition periodic.hh:24
constexpr bool hasSubProblemGlobalConstraints()
Definition assemblytraits.hh:30
Definition assembly/assembler.hh:46
bool allGridsSupportsMultithreading(const std::tuple< GridDiscretizations... > &gridDiscretizations)
Whether the grid views of all grid discretizations support multithreading.
Definition gridcapabilities.hh:44
const Scalar PengRobinsonMixture< Scalar, StaticParameters >::u
Definition pengrobinsonmixture.hh:138
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:58
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 assemblytraits.hh:43
An assembler for Jacobian and residual contribution per element (face-centered staggered methods) for...
Utilities for template meta programming.