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>
43#if HAVE_DUMUX_OLD_STAGGERED
44#include <dumux/multidomain/subdomainstaggeredlocalassembler.hh>
49template<std::
size_t id,
class TypeTag,
class Assembler, DiffMethod DM,
bool implicit>
61template<
class MDTraits,
class CMType, DiffMethod diffMethod,
bool useImplicitAssembly = true>
64 template<std::
size_t id>
65 using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
70 using Scalar =
typename MDTraits::Scalar;
72 template<std::
size_t id>
73 using LocalResidual =
typename MDTraits::template SubDomain<id>::LocalResidual;
75 template<std::
size_t id>
76 using GridVariables =
typename MDTraits::template SubDomain<id>::GridVariables;
78 template<std::
size_t id>
79 using GridGeometry =
typename MDTraits::template SubDomain<id>::GridGeometry;
81 template<std::
size_t id>
82 using Problem =
typename MDTraits::template SubDomain<id>::Problem;
94 {
return useImplicitAssembly; }
98 using ProblemTuple =
typename MDTraits::template TupleOfSharedPtrConst<Problem>;
99 using GridGeometryTuple =
typename MDTraits::template TupleOfSharedPtrConst<GridGeometry>;
100 using GridVariablesTuple =
typename MDTraits::template TupleOfSharedPtr<GridVariables>;
105 template<std::
size_t id>
108 template<
class DiscretizationMethod, std::
size_t id>
109 struct SubDomainAssemblerType;
111 template<std::
size_t id>
117 template<std::
size_t id>
118 struct SubDomainAssemblerType<DiscretizationMethods::CCMpfa, id>
120 using type = SubDomainCCLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
123 template<std::
size_t id,
class DM>
124 struct SubDomainAssemblerType<DiscretizationMethods::CVFE<DM>, id>
126 using type = SubDomainCVFELocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
129 template<std::
size_t id>
130 struct SubDomainAssemblerType<DiscretizationMethods::Staggered, id>
132 using type = SubDomainStaggeredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
135 template<std::
size_t id>
136 struct SubDomainAssemblerType<DiscretizationMethods::FCStaggered, id>
138 using type = SubDomainFaceCenteredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
141 template<std::
size_t id>
142 using SubDomainAssembler =
typename SubDomainAssemblerType<typename GridGeometry<id>::DiscretizationMethod,
id>::type;
157 , problemTuple_(std::move(
problem))
161 , isStationaryProblem_(true)
162 , warningIssued_(false)
164 static_assert(
isImplicit(),
"Explicit assembler for stationary problem doesn't make sense!");
165 std::cout <<
"Instantiated assembler for a stationary problem." << std::endl;
172 maybeComputeColors_();
184 std::shared_ptr<const TimeLoop> timeLoop,
187 , problemTuple_(std::move(
problem))
190 , timeLoop_(timeLoop)
192 , isStationaryProblem_(false)
193 , warningIssued_(false)
195 std::cout <<
"Instantiated assembler for an instationary problem." << std::endl;
202 maybeComputeColors_();
211 checkAssemblerState_();
215 using namespace Dune::Hybrid;
216 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainId)
218 auto& jacRow = (*jacobian_)[domainId];
219 auto& subRes = (*residual_)[domainId];
220 const auto& subSol = curSol[domainId];
221 this->assembleJacobianAndResidual_(domainId, jacRow, subRes, curSol);
223 const auto gridGeometry = std::get<domainId>(gridGeometryTuple_);
224 enforcePeriodicConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
225 enforceProblemConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
241 checkAssemblerState_();
246 using namespace Dune::Hybrid;
247 forEach(integralRange(Dune::Hybrid::size(r)), [&](
const auto domainId)
249 auto& subRes = r[domainId];
250 const auto& subSol = curSol[domainId];
251 this->assembleResidual_(domainId, subRes, curSol);
253 const auto gridGeometry = std::get<domainId>(gridGeometryTuple_);
254 enforcePeriodicConstraints_(domainId, subRes, *
gridGeometry, subSol);
255 enforceProblemConstraints_(domainId, subRes, *
gridGeometry, subSol);
265 std::shared_ptr<ResidualType> r)
271 setJacobianPattern_(*jacobian_);
272 setResidualSize_(*residual_);
281 jacobian_ = std::make_shared<JacobianMatrix>();
282 residual_ = std::make_shared<ResidualType>();
285 setJacobianPattern_(*jacobian_);
286 setResidualSize_(*residual_);
294 using namespace Dune::Hybrid;
295 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto i)
297 forEach(jac[i], [&](
auto& jacBlock)
299 using BlockType = std::decay_t<
decltype(jacBlock)>;
300 if (jacBlock.buildMode() == BlockType::BuildMode::unknown)
301 jacBlock.setBuildMode(BlockType::BuildMode::random);
302 else if (jacBlock.buildMode() != BlockType::BuildMode::random)
303 DUNE_THROW(Dune::NotImplemented,
"Only BCRS matrices with random build mode are supported at the moment");
313 setJacobianPattern_(*jacobian_);
314 setResidualSize_(*residual_);
315 maybeComputeColors_();
323 using namespace Dune::Hybrid;
324 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
325 { this->
gridVariables(domainId).update(curSol[domainId]); });
333 using namespace Dune::Hybrid;
334 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
335 { this->
gridVariables(domainId).resetTimeStep(curSol[domainId]); });
339 template<std::
size_t i>
340 std::size_t
numDofs(Dune::index_constant<i> domainId)
const
341 {
return std::get<domainId>(gridGeometryTuple_)->numDofs(); }
344 template<std::
size_t i>
345 const auto&
problem(Dune::index_constant<i> domainId)
const
346 {
return *std::get<domainId>(problemTuple_); }
349 template<std::
size_t i>
351 {
return *std::get<domainId>(gridGeometryTuple_); }
354 template<std::
size_t i>
355 const auto&
gridView(Dune::index_constant<i> domainId)
const
359 template<std::
size_t i>
361 {
return *std::get<domainId>(gridVariablesTuple_); }
364 template<std::
size_t i>
366 {
return *std::get<domainId>(gridVariablesTuple_); }
374 {
return *jacobian_; }
378 {
return *residual_; }
382 {
return *prevSol_; }
389 { timeLoop_ = timeLoop; isStationaryProblem_ = !(
static_cast<bool>(timeLoop)); }
402 {
return isStationaryProblem_; }
407 template<std::
size_t i>
409 {
return LocalResidual<i>(std::get<domainId>(problemTuple_).get(), timeLoop_.get()); }
421 using namespace Dune::Hybrid;
422 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainI)
424 forEach(integralRange(Dune::Hybrid::size(jac[domainI])), [&](
const auto domainJ)
426 const auto pattern = this->getJacobianPattern_(domainI, domainJ);
427 pattern.exportIdx(jac[domainI][domainJ]);
437 using namespace Dune::Hybrid;
438 forEach(integralRange(Dune::Hybrid::size(res)), [&](
const auto domainId)
439 { res[domainId].resize(this->
numDofs(domainId)); });
443 void resetResidual_()
447 residual_ = std::make_shared<ResidualType>();
448 setResidualSize_(*residual_);
455 void resetJacobian_()
459 jacobian_ = std::make_shared<JacobianMatrix>();
461 setJacobianPattern_(*jacobian_);
468 void maybeComputeColors_()
470 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
471 if (enableMultithreading_)
476 void checkAssemblerState_()
const
478 if (!isStationaryProblem_ && !prevSol_)
479 DUNE_THROW(Dune::InvalidStateException,
"Assembling instationary problem but previous solution was not set!");
481 if (isStationaryProblem_ && prevSol_)
482 DUNE_THROW(Dune::InvalidStateException,
"Assembling stationary problem but a previous solution was set."
483 <<
" Did you forget to set the timeLoop to make this problem instationary?");
486 template<std::
size_t i,
class JacRow,
class SubRes>
487 void assembleJacobianAndResidual_(Dune::index_constant<i> domainId, JacRow& jacRow, SubRes& subRes,
490 assemble_(domainId, [&](
const auto& element)
492 MultiDomainAssemblerSubDomainView view{*
this, domainId};
493 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
494 subDomainAssembler.assembleJacobianAndResidual(jacRow, subRes, gridVariablesTuple_);
498 template<std::
size_t i,
class SubRes>
499 void assembleResidual_(Dune::index_constant<i> domainId, SubRes& subRes,
502 assemble_(domainId, [&](
const auto& element)
504 MultiDomainAssemblerSubDomainView view{*
this, domainId};
505 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
506 subDomainAssembler.assembleResidual(subRes);
515 template<std::
size_t i,
class AssembleElementFunc>
516 void assemble_(Dune::index_constant<i> domainId, AssembleElementFunc&& assembleElement)
const
519 bool succeeded =
false;
524 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
526 if (enableMultithreading_)
529 domainId, std::forward<AssembleElementFunc>(assembleElement)
538 for (
const auto& element : elements(
gridView(domainId)))
539 assembleElement(element);
545 catch (NumericalProblem &e)
547 std::cout <<
"rank " <<
gridView(domainId).comm().rank()
548 <<
" caught an exception while assembling:" << e.what()
554 if (
gridView(domainId).comm().size() > 1)
555 succeeded =
gridView(domainId).comm().min(succeeded);
559 DUNE_THROW(NumericalProblem,
"A process did not succeed in linearizing the system");
563 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i==j),
int> = 0>
564 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
565 Dune::index_constant<j> domainJ)
const
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
584 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
585 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
591 if (m.first < m.second)
593 auto& jac = jacRow[domainI];
596 res[m.first] += res[m.second];
598 const auto end = jac[m.second].end();
599 for (
auto it = jac[m.second].begin(); it != end; ++it)
600 jac[m.first][it.index()] += (*it);
604 res[m.second] = curSol[m.second] - curSol[m.first];
607 auto setMatrixBlock = [] (
auto& matrixBlock,
double diagValue)
609 for (
int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
610 matrixBlock[eIdx][eIdx] = diagValue;
613 for (
auto it = jac[m.second].begin(); it != end; ++it)
615 auto& matrixBlock = *it;
618 assert(matrixBlock.N() == matrixBlock.M());
619 if(it.index() == m.second)
620 setMatrixBlock(matrixBlock, 1.0);
622 if(it.index() == m.first)
623 setMatrixBlock(matrixBlock, -1.0);
627 using namespace Dune::Hybrid;
630 auto& jacCoupling = jacRow[couplingDomainId];
632 for (
auto it = jacCoupling[m.second].begin(); it != jacCoupling[m.second].end(); ++it)
633 jacCoupling[m.first][it.index()] += (*it);
635 for (
auto it = jacCoupling[m.second].begin(); it != jacCoupling[m.second].end(); ++it)
644 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
645 void enforceProblemConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
649 auto& jac = jacRow[domainI];
650 auto applyDirichletConstraint = [&] (
const auto& dofIdx,
655 (res)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
657 auto& row = jac[dofIdx];
658 for (
auto col = row.begin(); col != row.end(); ++col)
659 row[col.index()][eqIdx] = 0.0;
661 jac[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
663 using namespace Dune::Hybrid;
666 auto& jacCoupling = jacRow[couplingDomainId];
668 auto& rowCoupling = jacCoupling[dofIdx];
669 for (
auto colCoupling = rowCoupling.begin(); colCoupling != rowCoupling.end(); ++colCoupling)
670 rowCoupling[colCoupling.index()][eqIdx] = 0.0;
675 for (
const auto& constraintData : this->
problem(domainI).constraints())
677 const auto& constraintInfo = constraintData.constraintInfo();
678 const auto& values = constraintData.values();
679 const auto dofIdx = constraintData.dofIndex();
681 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
683 if (constraintInfo.isConstraintEquation(eqIdx))
685 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
686 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
687 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
695 template<std::
size_t i,
class Res,
class GG,
class Sol>
696 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
702 if (m.first < m.second)
705 res[m.first] += res[m.second];
708 res[m.second] = curSol[m.second] - curSol[m.first];
715 template<std::
size_t i,
class Res,
class GG,
class Sol>
716 void enforceProblemConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
720 for (
const auto& constraintData : this->
problem(domainI).constraints())
722 const auto& constraintInfo = constraintData.constraintInfo();
723 const auto& values = constraintData.values();
724 const auto dofIdx = constraintData.dofIndex();
725 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
727 if (constraintInfo.isConstraintEquation(eqIdx))
729 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
730 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
731 res[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
739 ProblemTuple problemTuple_;
742 GridGeometryTuple gridGeometryTuple_;
745 GridVariablesTuple gridVariablesTuple_;
748 std::shared_ptr<const TimeLoop> timeLoop_;
754 bool isStationaryProblem_;
757 std::shared_ptr<JacobianMatrix> jacobian_;
758 std::shared_ptr<ResidualType> residual_;
761 mutable bool warningIssued_;
764 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
Subdomain-specific view on a multidomain assembler. Allows retrieval of sub-domain specific objects w...
Definition assemblerview.hh:33
A linear system assembler (residual and Jacobian) for finite volume schemes (box, tpfa,...
Definition multidomain/fvassembler.hh:63
std::size_t numDofs(Dune::index_constant< i > domainId) const
the number of dof locations of domain i
Definition multidomain/fvassembler.hh:340
void updateGridVariables(const SolutionVector &curSol)
Updates the grid variables with the given solution.
Definition multidomain/fvassembler.hh:321
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition multidomain/fvassembler.hh:311
typename MDTraits::SolutionVector SolutionVector
Definition multidomain/fvassembler.hh:85
typename MDTraits::template SubDomain< id >::Problem Problem
Definition multidomain/fvassembler.hh:82
JacobianMatrix & jacobian()
the full Jacobian matrix
Definition multidomain/fvassembler.hh:373
static constexpr bool isImplicit()
Returns true if the assembler considers implicit assembly.
Definition multidomain/fvassembler.hh:93
void assembleResidual(ResidualType &r, const SolutionVector &curSol)
assemble a residual r
Definition multidomain/fvassembler.hh:237
typename MDTraits::JacobianMatrix JacobianMatrix
Definition multidomain/fvassembler.hh:84
CMType CouplingManager
Definition multidomain/fvassembler.hh:88
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition multidomain/fvassembler.hh:230
void resetTimeStep(const SolutionVector &curSol)
Resets the grid variables to the last time step.
Definition multidomain/fvassembler.hh:331
const GridVariables< i > & gridVariables(Dune::index_constant< i > domainId) const
the grid variables of domain i
Definition multidomain/fvassembler.hh:365
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:395
typename MDTraits::template SubDomain< id >::GridVariables GridVariables
Definition multidomain/fvassembler.hh:76
const auto & gridGeometry(Dune::index_constant< i > domainId) const
Definition multidomain/fvassembler.hh:350
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition multidomain/fvassembler.hh:279
const auto & gridView(Dune::index_constant< i > domainId) const
the grid view of domain i
Definition multidomain/fvassembler.hh:355
typename MDTraits::template SubDomain< id >::GridGeometry GridGeometry
Definition multidomain/fvassembler.hh:79
const CouplingManager & couplingManager() const
Definition multidomain/fvassembler.hh:369
void setTimeManager(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition multidomain/fvassembler.hh:388
const SolutionVector & prevSol() const
Definition multidomain/fvassembler.hh:381
GridVariables< i > & gridVariables(Dune::index_constant< i > domainId)
Definition multidomain/fvassembler.hh:360
std::shared_ptr< CouplingManager > couplingManager_
Definition multidomain/fvassembler.hh:413
MDTraits Traits
Definition multidomain/fvassembler.hh:68
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:180
void setJacobianBuildMode(JacobianMatrix &jac) const
Sets the jacobian build mode.
Definition multidomain/fvassembler.hh:292
typename MDTraits::template SubDomain< id >::LocalResidual LocalResidual
Definition multidomain/fvassembler.hh:73
LocalResidual< i > localResidual(Dune::index_constant< i > domainId) const
Create a local residual object (used by the local assembler).
Definition multidomain/fvassembler.hh:408
const auto & problem(Dune::index_constant< i > domainId) const
Definition multidomain/fvassembler.hh:345
typename MDTraits::ResidualVector ResidualType
Definition multidomain/fvassembler.hh:86
MultiDomainFVAssembler(ProblemTuple problem, GridGeometryTuple gridGeometry, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager)
The constructor for stationary problems.
Definition multidomain/fvassembler.hh:152
void assembleJacobianAndResidual(const SolutionVector &curSol)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition multidomain/fvassembler.hh:209
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition multidomain/fvassembler.hh:401
typename MDTraits::Scalar Scalar
Definition multidomain/fvassembler.hh:70
ResidualType & residual()
the full residual vector
Definition multidomain/fvassembler.hh:377
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:264
The cell-centered scheme multidomain local assembler.
Definition multidomain/subdomaincclocalassembler.hh:270
Definition multidomain/fvassembler.hh:50
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:28
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:31
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
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...
constexpr bool hasPeriodicDofMap()
Definition periodic.hh:24
constexpr bool hasSubProblemGlobalConstraints()
Definition assemblytraits.hh:30
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.