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>
82 using GridGeometry =
typename MDTraits::template SubDomain<id>::GridGeometry;
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 GridGeometryTuple =
typename MDTraits::template TupleOfSharedPtrConst<GridGeometry>;
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>
121 struct SubDomainAssemblerType<DiscretizationMethods::CCMpfa, id>
123 using type = SubDomainCCLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
126 template<std::
size_t id,
class DM>
127 struct SubDomainAssemblerType<DiscretizationMethods::CVFE<DM>, id>
129 using type = SubDomainCVFELocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
132 template<std::
size_t id>
133 struct SubDomainAssemblerType<DiscretizationMethods::Staggered, id>
135 using type = SubDomainStaggeredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
138 template<std::
size_t id>
139 struct SubDomainAssemblerType<DiscretizationMethods::FCStaggered, id>
141 using type = SubDomainFaceCenteredLocalAssembler<id, SubDomainTypeTag<id>, SubDomainAssemblerView<id>, diffMethod,
isImplicit()>;
144 template<std::
size_t id>
145 using SubDomainAssembler =
typename SubDomainAssemblerType<typename GridGeometry<id>::DiscretizationMethod,
id>::type;
160 , problemTuple_(std::move(
problem))
164 , isStationaryProblem_(true)
165 , warningIssued_(false)
167 static_assert(
isImplicit(),
"Explicit assembler for stationary problem doesn't make sense!");
168 std::cout <<
"Instantiated assembler for a stationary problem." << std::endl;
175 maybeComputeColors_();
187 std::shared_ptr<const TimeLoop> timeLoop,
190 , problemTuple_(std::move(
problem))
193 , timeLoop_(timeLoop)
195 , isStationaryProblem_(false)
196 , warningIssued_(false)
198 std::cout <<
"Instantiated assembler for an instationary problem." << std::endl;
205 maybeComputeColors_();
214 checkAssemblerState_();
218 using namespace Dune::Hybrid;
219 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainId)
221 auto& jacRow = (*jacobian_)[domainId];
222 auto& subRes = (*residual_)[domainId];
223 const auto& subSol = curSol[domainId];
224 this->assembleJacobianAndResidual_(domainId, jacRow, subRes, curSol);
226 const auto gridGeometry = std::get<domainId>(gridGeometryTuple_);
227 enforcePeriodicConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
228 enforceProblemConstraints_(domainId, jacRow, subRes, *
gridGeometry, subSol);
244 checkAssemblerState_();
249 using namespace Dune::Hybrid;
250 forEach(integralRange(Dune::Hybrid::size(r)), [&](
const auto domainId)
252 auto& subRes = r[domainId];
253 const auto& subSol = curSol[domainId];
254 this->assembleResidual_(domainId, subRes, curSol);
256 const auto gridGeometry = std::get<domainId>(gridGeometryTuple_);
257 enforcePeriodicConstraints_(domainId, subRes, *
gridGeometry, subSol);
258 enforceProblemConstraints_(domainId, subRes, *
gridGeometry, subSol);
268 std::shared_ptr<ResidualType> r)
274 setJacobianPattern_(*jacobian_);
275 setResidualSize_(*residual_);
284 jacobian_ = std::make_shared<JacobianMatrix>();
285 residual_ = std::make_shared<ResidualType>();
288 setJacobianPattern_(*jacobian_);
289 setResidualSize_(*residual_);
297 using namespace Dune::Hybrid;
298 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto i)
300 forEach(jac[i], [&](
auto& jacBlock)
302 using BlockType = std::decay_t<
decltype(jacBlock)>;
303 if (jacBlock.buildMode() == BlockType::BuildMode::unknown)
304 jacBlock.setBuildMode(BlockType::BuildMode::random);
305 else if (jacBlock.buildMode() != BlockType::BuildMode::random)
306 DUNE_THROW(Dune::NotImplemented,
"Only BCRS matrices with random build mode are supported at the moment");
316 setJacobianPattern_(*jacobian_);
317 setResidualSize_(*residual_);
318 maybeComputeColors_();
326 using namespace Dune::Hybrid;
327 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
328 { this->
gridVariables(domainId).update(curSol[domainId]); });
336 using namespace Dune::Hybrid;
337 forEach(integralRange(Dune::Hybrid::size(gridVariablesTuple_)), [&](
const auto domainId)
338 { this->
gridVariables(domainId).resetTimeStep(curSol[domainId]); });
342 template<std::
size_t i>
343 std::size_t
numDofs(Dune::index_constant<i> domainId)
const
344 {
return std::get<domainId>(gridGeometryTuple_)->numDofs(); }
347 template<std::
size_t i>
348 const auto&
problem(Dune::index_constant<i> domainId)
const
349 {
return *std::get<domainId>(problemTuple_); }
352 template<std::
size_t i>
354 {
return *std::get<domainId>(gridGeometryTuple_); }
357 template<std::
size_t i>
358 const auto&
gridView(Dune::index_constant<i> domainId)
const
362 template<std::
size_t i>
364 {
return *std::get<domainId>(gridVariablesTuple_); }
367 template<std::
size_t i>
369 {
return *std::get<domainId>(gridVariablesTuple_); }
377 {
return *jacobian_; }
381 {
return *residual_; }
385 {
return *prevSol_; }
392 { timeLoop_ = timeLoop; isStationaryProblem_ = !(
static_cast<bool>(timeLoop)); }
405 {
return isStationaryProblem_; }
410 template<std::
size_t i>
412 {
return LocalResidual<i>(std::get<domainId>(problemTuple_).get(), timeLoop_.get()); }
424 using namespace Dune::Hybrid;
425 forEach(std::make_index_sequence<JacobianMatrix::N()>(), [&](
const auto domainI)
427 forEach(integralRange(Dune::Hybrid::size(jac[domainI])), [&](
const auto domainJ)
429 const auto pattern = this->getJacobianPattern_(domainI, domainJ);
430 pattern.exportIdx(jac[domainI][domainJ]);
440 using namespace Dune::Hybrid;
441 forEach(integralRange(Dune::Hybrid::size(res)), [&](
const auto domainId)
442 { res[domainId].resize(this->
numDofs(domainId)); });
446 void resetResidual_()
450 residual_ = std::make_shared<ResidualType>();
451 setResidualSize_(*residual_);
458 void resetJacobian_()
462 jacobian_ = std::make_shared<JacobianMatrix>();
464 setJacobianPattern_(*jacobian_);
471 void maybeComputeColors_()
473 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
474 if (enableMultithreading_)
479 void checkAssemblerState_()
const
481 if (!isStationaryProblem_ && !prevSol_)
482 DUNE_THROW(Dune::InvalidStateException,
"Assembling instationary problem but previous solution was not set!");
484 if (isStationaryProblem_ && prevSol_)
485 DUNE_THROW(Dune::InvalidStateException,
"Assembling stationary problem but a previous solution was set."
486 <<
" Did you forget to set the timeLoop to make this problem instationary?");
489 template<std::
size_t i,
class JacRow,
class SubRes>
490 void assembleJacobianAndResidual_(Dune::index_constant<i> domainId, JacRow& jacRow, SubRes& subRes,
493 assemble_(domainId, [&](
const auto& element)
495 MultiDomainAssemblerSubDomainView view{*
this, domainId};
496 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
497 subDomainAssembler.assembleJacobianAndResidual(jacRow, subRes, gridVariablesTuple_);
501 template<std::
size_t i,
class SubRes>
502 void assembleResidual_(Dune::index_constant<i> domainId, SubRes& subRes,
505 assemble_(domainId, [&](
const auto& element)
507 MultiDomainAssemblerSubDomainView view{*
this, domainId};
508 SubDomainAssembler<i> subDomainAssembler(view, element, curSol, *
couplingManager_);
509 subDomainAssembler.assembleResidual(subRes);
518 template<std::
size_t i,
class AssembleElementFunc>
519 void assemble_(Dune::index_constant<i> domainId, AssembleElementFunc&& assembleElement)
const
522 bool succeeded =
false;
527 if constexpr (CouplingManagerSupportsMultithreadedAssembly<CouplingManager>::value)
529 if (enableMultithreading_)
532 domainId, std::forward<AssembleElementFunc>(assembleElement)
541 for (
const auto& element : elements(
gridView(domainId)))
542 assembleElement(element);
548 catch (NumericalProblem &e)
550 std::cout <<
"rank " <<
gridView(domainId).comm().rank()
551 <<
" caught an exception while assembling:" << e.what()
557 if (
gridView(domainId).comm().size() > 1)
558 succeeded =
gridView(domainId).comm().min(succeeded);
562 DUNE_THROW(NumericalProblem,
"A process did not succeed in linearizing the system");
566 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i==j),
int> = 0>
567 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
568 Dune::index_constant<j> domainJ)
const
577 template<std::
size_t i, std::
size_t j,
typename std::enable_if_t<(i!=j),
int> = 0>
578 Dune::MatrixIndexSet getJacobianPattern_(Dune::index_constant<i> domainI,
579 Dune::index_constant<j> domainJ)
const
587 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
588 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
594 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
595 if (std::ranges::all_of(periodicallyMappedDofs, [&](
auto second){
return m.first < second; }))
597 for (
const auto& second : periodicallyMappedDofs)
599 auto& jac = jacRow[domainI];
602 res[m.first] += res[second];
604 const auto end = jac[second].end();
605 for (
auto it = jac[second].begin(); it != end; ++it)
606 jac[m.first][it.index()] += (*it);
610 res[second] = curSol[second] - curSol[m.first];
613 auto setMatrixBlock = [] (
auto& matrixBlock,
double diagValue)
615 for (
int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
616 matrixBlock[eIdx][eIdx] = diagValue;
619 for (
auto it = jac[second].begin(); it != end; ++it)
621 auto& matrixBlock = *it;
624 assert(matrixBlock.N() == matrixBlock.M());
625 if(it.index() == second)
626 setMatrixBlock(matrixBlock, 1.0);
628 if(it.index() == m.first)
629 setMatrixBlock(matrixBlock, -1.0);
633 using namespace Dune::Hybrid;
636 auto& jacCoupling = jacRow[couplingDomainId];
638 for (
auto it = jacCoupling[second].begin(); it != jacCoupling[second].end(); ++it)
639 jacCoupling[m.first][it.index()] += (*it);
641 for (
auto it = jacCoupling[second].begin(); it != jacCoupling[second].end(); ++it)
651 template<std::
size_t i,
class JacRow,
class Res,
class GG,
class Sol>
652 void enforceProblemConstraints_(Dune::index_constant<i> domainI, JacRow& jacRow, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
656 auto& jac = jacRow[domainI];
657 auto applyDirichletConstraint = [&] (
const auto& dofIdx,
662 (res)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
664 auto& row = jac[dofIdx];
665 for (
auto col = row.begin(); col != row.end(); ++col)
666 row[col.index()][eqIdx] = 0.0;
668 jac[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
670 using namespace Dune::Hybrid;
673 auto& jacCoupling = jacRow[couplingDomainId];
675 auto& rowCoupling = jacCoupling[dofIdx];
676 for (
auto colCoupling = rowCoupling.begin(); colCoupling != rowCoupling.end(); ++colCoupling)
677 rowCoupling[colCoupling.index()][eqIdx] = 0.0;
682 for (
const auto& constraintData : this->
problem(domainI).constraints())
684 const auto& constraintInfo = constraintData.constraintInfo();
685 const auto& values = constraintData.values();
686 const auto dofIdx = constraintData.dofIndex();
688 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
690 if (constraintInfo.isConstraintEquation(eqIdx))
692 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
693 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
694 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
702 template<std::
size_t i,
class Res,
class GG,
class Sol>
703 void enforcePeriodicConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
709 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
710 if (std::ranges::all_of(periodicallyMappedDofs, [&](
auto second){
return m.first < second; }))
712 for (
const auto& second : periodicallyMappedDofs)
715 res[m.first] += res[second];
718 res[second] = curSol[second] - curSol[m.first];
726 template<std::
size_t i,
class Res,
class GG,
class Sol>
727 void enforceProblemConstraints_(Dune::index_constant<i> domainI, Res& res,
const GG&
gridGeometry,
const Sol& curSol)
const
731 for (
const auto& constraintData : this->
problem(domainI).constraints())
733 const auto& constraintInfo = constraintData.constraintInfo();
734 const auto& values = constraintData.values();
735 const auto dofIdx = constraintData.dofIndex();
736 for (
int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
738 if (constraintInfo.isConstraintEquation(eqIdx))
740 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
741 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
742 res[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
750 ProblemTuple problemTuple_;
753 GridGeometryTuple gridGeometryTuple_;
756 GridVariablesTuple gridVariablesTuple_;
759 std::shared_ptr<const TimeLoop> timeLoop_;
765 bool isStationaryProblem_;
768 std::shared_ptr<JacobianMatrix> jacobian_;
769 std::shared_ptr<ResidualType> residual_;
772 mutable bool warningIssued_;
775 bool enableMultithreading_ =
false;
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:183
MultiDomainFVAssembler(ProblemTuple problem, GridGeometryTuple gridGeometry, GridVariablesTuple gridVariables, std::shared_ptr< CouplingManager > couplingManager)
The constructor for stationary problems.
Definition multidomain/fvassembler.hh:155
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