version 3.11-dev
Loading...
Searching...
No Matches
multistageassembler.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//
13#ifndef DUMUX_EXPERIMENTAL_MULTISTAGE_ASSEMBLER_HH
14#define DUMUX_EXPERIMENTAL_MULTISTAGE_ASSEMBLER_HH
15
16#include <vector>
17#include <deque>
18#include <memory>
19#include <utility>
20
21#include <dune/common/exceptions.hh>
22
26
29
34
37
40
41namespace Dumux::Experimental {
42
53template<class TypeTag, DiffMethod diffMethod>
55{
57 using GridView = typename GridGeo::GridView;
59 using Element = typename GridView::template Codim<0>::Entity;
60 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
61
63 using LocalAssembler = typename Detail::LocalAssemblerChooser_t<TypeTag, ThisType, diffMethod, /*isImplicit=*/true>;
64
65public:
71
73
74 using GridGeometry = GridGeo;
76
82 MultiStageAssembler(std::shared_ptr<const Problem> problem,
83 std::shared_ptr<const GridGeometry> gridGeometry,
84 std::shared_ptr<GridVariables> gridVariables,
85 std::shared_ptr<const Experimental::MultiStageMethod<Scalar>> msMethod,
87 : timeSteppingMethod_(msMethod)
88 , problem_(problem)
89 , gridGeometry_(gridGeometry)
90 , gridVariables_(gridVariables)
91 , prevSol_(&prevSol)
92 {
93 if (!timeSteppingMethod_->implicit())
94 DUNE_THROW(Dune::NotImplemented,
95 "MultiStageAssembler only supports implicit (DIRK-type) time-stepping schemes; "
96 "the underlying CVFELocalAssembler has no explicit-scheme specialization.");
97
99 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
101 && getParam<bool>("Assembly.Multithreading", true);
102
103 maybeComputeColors_();
104 }
105
111 {
112 resetJacobian_();
113 resetResidual_();
114 markConstrainedDofs_();
115
116 spatialOperatorEvaluations_.back() = 0.0;
117 temporalOperatorEvaluations_.back() = 0.0;
118
119 if (stageParams_->size() != spatialOperatorEvaluations_.size())
120 DUNE_THROW(Dune::InvalidStateException, "Wrong number of residuals");
121
122 assemble_([&](const Element& element)
123 {
124 LocalAssembler localAssembler(*this, element, curSol);
125 localAssembler.assembleJacobianAndResidual(
126 *jacobian_, *residual_, *gridVariables_,
127 *stageParams_,
128 temporalOperatorEvaluations_.back(),
129 spatialOperatorEvaluations_.back(),
130 constrainedDofs_
131 );
132 });
133
134 // assemble the full residual for the time integration stage
135 auto constantResidualComponent = (*residual_);
136 constantResidualComponent = 0.0;
137 for (std::size_t k = 0; k < stageParams_->size()-1; ++k)
138 {
139 if (!stageParams_->skipTemporal(k))
140 constantResidualComponent.axpy(stageParams_->temporalWeight(k), temporalOperatorEvaluations_[k]);
141 if (!stageParams_->skipSpatial(k))
142 constantResidualComponent.axpy(stageParams_->spatialWeight(k), spatialOperatorEvaluations_[k]);
143 }
144
145 // masked summation of constant residual component onto this stage's residual component
146 for (std::size_t i = 0; i < constantResidualComponent.size(); ++i)
147 for (std::size_t ii = 0; ii < constantResidualComponent[i].size(); ++ii)
148 (*residual_)[i][ii] += constrainedDofs_[i][ii] > 0.5 ? 0.0 : constantResidualComponent[i][ii];
149
150 applyDirichletConstraints_(curSol);
151 }
152
157 {
158 resetResidual_();
159 markConstrainedDofs_();
160
161 if (stageParams_->size() != spatialOperatorEvaluations_.size())
162 DUNE_THROW(Dune::InvalidStateException, "Wrong number of residuals");
163
164 assembleOperatorEvaluations_(curSol);
165
166 const auto k = stageParams_->size() - 1;
167 (*residual_) = 0.0;
168 residual_->axpy(stageParams_->temporalWeight(k), temporalOperatorEvaluations_.back());
169 residual_->axpy(stageParams_->spatialWeight(k), spatialOperatorEvaluations_.back());
170
171 auto constantResidualComponent = (*residual_);
172 constantResidualComponent = 0.0;
173 for (std::size_t i = 0; i < k; ++i)
174 {
175 if (!stageParams_->skipTemporal(i))
176 constantResidualComponent.axpy(stageParams_->temporalWeight(i), temporalOperatorEvaluations_[i]);
177 if (!stageParams_->skipSpatial(i))
178 constantResidualComponent.axpy(stageParams_->spatialWeight(i), spatialOperatorEvaluations_[i]);
179 }
180
181 for (std::size_t i = 0; i < constantResidualComponent.size(); ++i)
182 for (std::size_t ii = 0; ii < constantResidualComponent[i].size(); ++ii)
183 (*residual_)[i][ii] += constrainedDofs_[i][ii] > 0.5 ? 0.0 : constantResidualComponent[i][ii];
184
185 applyDirichletResidual_(curSol);
186 }
187
193 {
194 jacobian_ = std::make_shared<JacobianMatrix>();
195 jacobian_->setBuildMode(JacobianMatrix::random);
196 residual_ = std::make_shared<ResidualType>();
197
198 setResidualSize_(*residual_);
199 setJacobianPattern_();
200 }
201
206 {
207 setResidualSize_(*residual_);
208 setJacobianPattern_();
209 maybeComputeColors_();
210 }
211
213 std::size_t numDofs() const
214 { return gridGeometry_->numDofs(); }
215
217 const Problem& problem() const
218 { return *problem_; }
219
222 { return *gridGeometry_; }
223
226 { return *gridGeometry_; }
227
229 const GridView& gridView() const
230 { return gridGeometry().gridView(); }
231
234 { return *gridVariables_; }
235
238 { return *gridVariables_; }
239
242 { return *jacobian_; }
243
246 { return *residual_; }
247
249 const SolutionVector& prevSol() const
250 { return *prevSol_; }
251
257 LocalResidual localResidual() const
258 { return LocalResidual(problem_.get(), nullptr); }
259
264 { gridVariables().update(cursol); }
265
269 void resetTimeStep(const SolutionVector &cursol)
270 {
271 gridVariables().resetTimeStep(cursol);
272 this->clearStages();
273 }
274
276 {
277 spatialOperatorEvaluations_.clear();
278 temporalOperatorEvaluations_.clear();
279 stageParams_.reset();
280 }
281
282 template<class StageParamsArg>
283 void prepareStage(SolutionVector& x, StageParamsArg params)
284 {
285 stageParams_ = std::move(params);
286 const auto curStage = stageParams_->size() - 1;
287
288 // in the first stage, also assemble the residual
289 // at the previous time level (stage 0 residual)
290 if (curStage == 1)
291 {
292 setProblemTime_(*problem_, stageParams_->timeAtStage(0));
293
294 resetResidual_();
295
296 assert(spatialOperatorEvaluations_.size() >= 0);
297 if (spatialOperatorEvaluations_.size() == 0)
298 {
299 spatialOperatorEvaluations_.push_back(*residual_);
300 temporalOperatorEvaluations_.push_back(*residual_);
301 assembleOperatorEvaluations_(*prevSol_);
302 }
303
304 // we don't delete the first stage so it can be reused in a restarted
305 // time integration step. The evaluations are only deleted
306 // when explicitly requested by calling clearStages().
307 // So if here the vector is non-empty, we don't need to evaluate again
308 // (this should only occur if we are restarting time integration, e.g.
309 // with a different time step size)
310 else if (spatialOperatorEvaluations_.size() > 0)
311 {
313 spatialOperatorEvaluations_.resize(1);
314 temporalOperatorEvaluations_.resize(1);
315 }
316 }
317
318 if (spatialOperatorEvaluations_.size() != curStage)
319 DUNE_THROW(Dune::InvalidStateException,
320 "Invalid state. Maybe you forgot to call clearStages()");
321
322 // The evaluations recorded while solving the previous stage belong to the last iterate
323 // the solver assembled, which is not the stage solution for a solver that stops after an
324 // update (e.g. Newton on the shift criterion) or assembles only once (a linear solver).
325 if (curStage > 1)
326 {
327 setProblemTime_(*problem_, stageParams_->timeAtStage(curStage-1));
328 assembleOperatorEvaluations_(x);
329 }
330
331 setProblemTime_(*problem_, stageParams_->timeAtStage(curStage));
332
333 resetResidual_();
334
335 // allocate memory for this stage
336 spatialOperatorEvaluations_.push_back(*residual_);
337 temporalOperatorEvaluations_.push_back(*residual_);
338 }
339
342 { return false; }
343
344 bool isImplicit() const
345 { return timeSteppingMethod_->implicit(); }
346
348 std::pair<Scalar, Scalar> currentStageWeights() const
349 {
350 if (!stageParams_)
351 DUNE_THROW(Dune::InvalidStateException, "No stage params set. Call prepareStage first.");
352 const auto k = stageParams_->size() - 1;
353 return {stageParams_->temporalWeight(k), stageParams_->spatialWeight(k)};
354 }
355
356private:
358 void assembleOperatorEvaluations_(const SolutionVector& sol)
359 {
360 spatialOperatorEvaluations_.back() = 0.0;
361 temporalOperatorEvaluations_.back() = 0.0;
362 assemble_([&](const Element& element)
363 {
364 LocalAssembler localAssembler(*this, element, sol);
365 localAssembler.assembleCurrentResidual(temporalOperatorEvaluations_.back(),
366 spatialOperatorEvaluations_.back());
367 });
368 }
369
373 void setJacobianPattern_()
374 {
375 const auto numDofs = this->numDofs();
376 jacobian_->setSize(numDofs, numDofs);
377 getJacobianPattern<true>(gridGeometry()).exportIdx(*jacobian_);
378 }
379
381 void setResidualSize_(ResidualType& res)
382 { res.resize(numDofs()); }
383
385 void maybeComputeColors_()
386 {
387 if (enableMultithreading_)
388 elementSets_ = computeColoring(gridGeometry()).sets;
389 }
390
391 // reset the residual vector to 0.0
392 void resetResidual_()
393 {
394 if(!residual_)
395 {
396 residual_ = std::make_shared<ResidualType>();
397 setResidualSize_(*residual_);
398 }
399
400 setResidualSize_(constrainedDofs_);
401
402 (*residual_) = 0.0;
403 constrainedDofs_ = 0.0;
404 }
405
406 // reset the Jacobian matrix to 0.0
407 void resetJacobian_()
408 {
409 if(!jacobian_)
410 {
411 jacobian_ = std::make_shared<JacobianMatrix>();
412 jacobian_->setBuildMode(JacobianMatrix::random);
413 setJacobianPattern_();
414 }
415
416 *jacobian_ = 0.0;
417 }
418
422 void markConstrainedDofs_()
423 {
425 {
426 for (const auto& constraintData : problem_->constraints())
427 {
428 const auto& info = constraintData.constraintInfo();
429 const auto dofIdx = constraintData.dofIndex();
430 for (int eqIdx = 0; eqIdx < info.size(); ++eqIdx)
431 if (info.isConstraintEquation(eqIdx))
432 constrainedDofs_[dofIdx][eqIdx] = 1.0;
433 }
434 }
435 }
436
438 void applyDirichletConstraints_(const SolutionVector& curSol)
439 {
441 {
442 for (const auto& constraintData : problem_->constraints())
443 {
444 const auto& info = constraintData.constraintInfo();
445 const auto& values = constraintData.values();
446 const auto dofIdx = constraintData.dofIndex();
447 for (int eqIdx = 0; eqIdx < info.size(); ++eqIdx)
448 {
449 if (info.isConstraintEquation(eqIdx))
450 {
451 const auto pvIdx = info.eqToPriVarIndex(eqIdx);
452 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
453
454 auto& row = (*jacobian_)[dofIdx];
455 for (auto col = row.begin(); col != row.end(); ++col)
456 row[col.index()][eqIdx] = 0.0;
457
458 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
459 }
460 }
461 }
462 }
463 }
464
466 void applyDirichletResidual_(const SolutionVector& curSol)
467 {
469 {
470 for (const auto& constraintData : problem_->constraints())
471 {
472 const auto& info = constraintData.constraintInfo();
473 const auto& values = constraintData.values();
474 const auto dofIdx = constraintData.dofIndex();
475 for (int eqIdx = 0; eqIdx < info.size(); ++eqIdx)
476 if (info.isConstraintEquation(eqIdx))
477 {
478 const auto pvIdx = info.eqToPriVarIndex(eqIdx);
479 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
480 }
481 }
482 }
483 }
484
490 template<typename AssembleElementFunc>
491 void assemble_(AssembleElementFunc&& assembleElement) const
492 {
493 // a state that will be checked on all processes
494 bool succeeded = false;
495
496 try
497 {
498 if (enableMultithreading_)
499 {
500 assert(elementSets_.size() > 0);
501
502 for (const auto& elements : elementSets_)
503 {
504 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
505 {
506 const auto element = gridView().grid().entity(elements[i]);
507 assembleElement(element);
508 });
509 }
510 }
511 else
512 for (const auto& element : elements(gridView()))
513 assembleElement(element);
514
515 succeeded = true;
516 }
517 catch (NumericalProblem &e)
518 {
519 std::cout << "rank " << gridView().comm().rank()
520 << " caught an exception while assembling:" << e.what()
521 << "\n";
522 succeeded = false;
523 }
524
525 if (gridView().comm().size() > 1)
526 succeeded = gridView().comm().min(succeeded);
527
528 if (!succeeded)
529 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
530 }
531
532 template<class P>
533 void setProblemTime_(const P& p, const Scalar t)
534 {
535 if constexpr (requires { p.setTime(t); })
536 p.setTime(t);
537 else
538 static_assert(!requires (P& q) { q.setTime(Scalar{}); },
539 "The multi-stage assembler sets the stage time through a const problem: setTime has to be const.");
540 }
541
542 std::shared_ptr<const Experimental::MultiStageMethod<Scalar>> timeSteppingMethod_;
543 std::vector<ResidualType> spatialOperatorEvaluations_;
544 std::vector<ResidualType> temporalOperatorEvaluations_;
545 ResidualType constrainedDofs_;
546 std::shared_ptr<const StageParams> stageParams_;
547
549 std::shared_ptr<const Problem> problem_;
550
552 std::shared_ptr<const GridGeometry> gridGeometry_;
553
555 std::shared_ptr<GridVariables> gridVariables_;
556
558 const SolutionVector* prevSol_ = nullptr;
559
561 std::shared_ptr<JacobianMatrix> jacobian_;
562 std::shared_ptr<ResidualType> residual_;
563
565 bool enableMultithreading_ = false;
566 std::deque<std::vector<ElementSeed>> elementSets_;
567};
568
569} // namespace Dumux::Experimental
570
571#endif
A linear system assembler (residual and Jacobian) for general discretization schemes.
void updateGridVariables(const SolutionVector &cursol)
Update the grid variables.
Definition multistageassembler.hh:263
LocalResidual localResidual() const
Create a local residual object (used by the local assembler).
Definition multistageassembler.hh:257
void resetTimeStep(const SolutionVector &cursol)
Reset the gridVariables.
Definition multistageassembler.hh:269
const GridGeometry & gridDiscretization() const
The grid discretization.
Definition multistageassembler.hh:225
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition multistageassembler.hh:205
GridGeo GridGeometry
Definition multistageassembler.hh:74
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition multistageassembler.hh:72
GetPropType< TypeTag, Properties::Problem > Problem
Definition multistageassembler.hh:75
void assembleResidual(const SolutionVector &curSol)
Assembles the residual of the current stage for the given solution.
Definition multistageassembler.hh:156
ResidualType & residual()
The residual vector (rhs).
Definition multistageassembler.hh:245
bool isImplicit() const
Definition multistageassembler.hh:344
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition multistageassembler.hh:68
bool isStationaryProblem() const
TODO get rid of this (called by Newton but shouldn't be necessary).
Definition multistageassembler.hh:341
const SolutionVector & prevSol() const
The solution of the previous time step.
Definition multistageassembler.hh:249
MultiStageAssembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridGeometry > gridGeometry, std::shared_ptr< GridVariables > gridVariables, std::shared_ptr< const Experimental::MultiStageMethod< Scalar > > msMethod, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition multistageassembler.hh:82
const GridView & gridView() const
The gridview.
Definition multistageassembler.hh:229
Experimental::MultiStageParams< Scalar > StageParams
Definition multistageassembler.hh:67
void prepareStage(SolutionVector &x, StageParamsArg params)
Definition multistageassembler.hh:283
const GridVariables & gridVariables() const
The global grid variables.
Definition multistageassembler.hh:237
void clearStages()
Definition multistageassembler.hh:275
std::pair< Scalar, Scalar > currentStageWeights() const
The temporal and spatial weight of the current stage.
Definition multistageassembler.hh:348
const Problem & problem() const
The problem.
Definition multistageassembler.hh:217
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition multistageassembler.hh:192
void assembleJacobianAndResidual(const SolutionVector &curSol)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition multistageassembler.hh:110
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition multistageassembler.hh:66
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition multistageassembler.hh:69
GridVariables & gridVariables()
The global grid variables.
Definition multistageassembler.hh:233
JacobianMatrix & jacobian()
The jacobian matrix.
Definition multistageassembler.hh:241
typename Dumux::Detail::NativeDuneVectorType< SolutionVector >::type ResidualType
Definition multistageassembler.hh:70
const GridGeometry & gridGeometry() const
The global finite volume geometry.
Definition multistageassembler.hh:221
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition multistageassembler.hh:213
Abstract interface for one-step multi-stage method parameters in Shu/Osher form.
Definition multistagemethods.hh:75
Data object for the parameters of a given stage.
Definition multistagetimestepper.hh:31
Coloring schemes for shared-memory-parallel assembly.
Defines all properties used in Dumux.
An enum class to define various differentiation methods available in order to compute the derivatives...
Helper to extract native Dune vector types from particular Dumux types.
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
constexpr bool isSerial()
Checking whether the backend is serial.
Definition multithreading.hh:45
void parallelFor(const std::size_t count, const FunctorType &functor)
A parallel for loop (multithreading).
Definition parallel_for.hh:160
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.
Parameters for different multistage time stepping methods.
A time stepper performing a single time step of a transient simulation.
Multithreading in Dumux.
constexpr bool hasGlobalConstraints()
Definition assembly/assembler.hh:66
typename LocalAssemblerChooser< typename GetPropType< TypeTag, Properties::GridGeometry >::DiscretizationMethod >::template type< TypeTag, Impl, diffMethod, isImplicit > LocalAssemblerChooser_t
Definition assembly/assembler.hh:57
Definition assembly/assembler.hh:44
bool supportsMultithreading(const GridView &gridView)
Definition gridcapabilities.hh:36
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition coloring.hh:243
Parallel for loop (multithreading).
typename NativeDuneVectorTypeImpl< V, Dune::Std::is_detected< Detail::DuneVectors::StateDetector, V >{} >::type type
Definition dunevectors.hh:57
Traits specifying if a given discretization tag supports coloring.
Definition coloring.hh:296
Type traits to be used with vector types.