3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
common/timeloop.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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_TIME_LOOP_HH
25#define DUMUX_TIME_LOOP_HH
26
27#include <algorithm>
28#include <queue>
29#include <iomanip>
30
31#include <dune/common/float_cmp.hh>
32#include <dune/common/timer.hh>
33
34#include <dune/common/parallel/communication.hh>
35
36#include <dune/common/parallel/mpihelper.hh>
37#include <dune/common/exceptions.hh>
38
40#include <dumux/io/format.hh>
41
42namespace Dumux {
43
66template<class Scalar>
68{
69public:
71 virtual ~TimeLoopBase() {};
72
78 virtual Scalar time() const = 0;
79
83 virtual Scalar timeStepSize() const = 0;
84
88 virtual Scalar maxTimeStepSize() const = 0;
89
93 virtual void advanceTimeStep() = 0;
94
99 virtual void setTimeStepSize(Scalar dt) = 0;
100
104 virtual bool finished() const = 0;
105};
106
111template <class Scalar>
112class TimeLoop : public TimeLoopBase<Scalar>
113{
114public:
115 TimeLoop(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose = true)
116 : timer_(false)
117 {
118 reset(startTime, dt, tEnd, verbose);
119 }
120
129 void start()
130 {
131 timer_.start();
132 }
133
138 double stop()
139 {
140 return timer_.stop();
141 }
142
147 {
148 timer_.reset();
149 }
150
154 void reset(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose = true)
155 {
156 verbose_ =
157 verbose &&
158 Dune::MPIHelper::getCommunication().rank() == 0;
159
160 time_ = startTime;
161 endTime_ = tEnd;
162
164 userSetMaxTimeStepSize_ = std::numeric_limits<Scalar>::max();
165 timeStepIdx_ = 0;
166 finished_ = false;
169
170 // ensure that dt is not greater than tEnd-startTime
171 setTimeStepSize(dt);
172
173 timer_.stop();
174 timer_.reset();
175 }
176
180 void advanceTimeStep() override
181 {
182 timeStepIdx_++;
185
186 // compute how long the last time step took
187 const auto cpuTime = wallClockTime();
189 timeAfterLastTimeStep_ = cpuTime;
190
191 // ensure that using current dt we don't exceed tEnd in next time step
193 }
194
201 void setTime(Scalar t)
202 { time_ = t; }
203
210 void setTime(Scalar t, int stepIdx)
211 { time_ = t; timeStepIdx_ = stepIdx; }
212
218 Scalar time() const final
219 { return time_; }
220
224 Scalar endTime() const
225 { return endTime_; }
226
232 void setEndTime(Scalar t)
233 {
234 endTime_ = t;
235 if (verbose_)
236 std::cout << Fmt::format("Set new end time to t = {:.5g} seconds.\n", t);
237 }
238
242 double wallClockTime() const
243 { return timer_.elapsed(); }
244
255 void setTimeStepSize(Scalar dt) final
256 {
257 using std::min;
258 timeStepSize_ = min(dt, maxTimeStepSize());
259 if (!finished() && Dune::FloatCmp::le(timeStepSize_, 0.0, 1e-14*endTime_))
260 std::cerr << Fmt::format("You have set a very small timestep size (dt = {:.5g}).", timeStepSize_)
261 << " This might lead to numerical problems!\n";
262 }
263
270 void setMaxTimeStepSize(Scalar maxDt)
271 {
274 }
275
281 Scalar timeStepSize() const final
282 { return timeStepSize_; }
283
288 int timeStepIndex() const
289 { return timeStepIdx_; }
290
294 Scalar previousTimeStepSize() const
295 { return previousTimeStepSize_; }
296
304 void setFinished(bool finished = true)
305 { finished_ = finished; }
306
313 bool finished() const override
314 {
315 return finished_ || endTime_-time_ < 1e-10*time_;
316 }
317
322 bool willBeFinished() const
323 {
325 }
326
332 Scalar maxTimeStepSize() const override
333 {
334 if (finished())
335 return 0.0;
336
337 using std::min; using std::max;
338 return min(userSetMaxTimeStepSize_, max<Scalar>(0.0, endTime_ - time_));
339 }
340
345 void reportTimeStep() const
346 {
347 if (verbose_)
348 {
349 const auto cpuTime = wallClockTime();
350 using std::round;
351 const auto percent = round( time_ / endTime_ * 100 );
352 std::cout << Fmt::format("[{:3.0f}%] ", percent)
353 << Fmt::format("Time step {} done in {:.2g} seconds. ", timeStepIdx_, timeStepWallClockTime_)
354 << Fmt::format("Wall clock time: {:.5g}, time: {:.5g}, time step size: {:.5g}\n", cpuTime, time_, previousTimeStepSize_);
355 }
356 }
357
361 template< class Communicator = Dune::Communication<typename Dune::MPIHelper::MPICommunicator> >
362 void finalize(const Communicator& comm = Dune::MPIHelper::getCommunication())
363 {
364 auto cpuTime = timer_.stop();
365
366 if (verbose_)
367 std::cout << Fmt::format("Simulation took {:.5g} seconds on {} processes.\n", cpuTime, comm.size());
368
369 if (comm.size() > 1)
370 cpuTime = comm.sum(cpuTime);
371
372 if (verbose_)
373 std::cout << Fmt::format("The cumulative CPU time was {:.5g} seconds.\n", cpuTime);
374 }
375
377 bool verbose() const
378 { return verbose_; }
379
381 void setVerbose(bool verbose = true)
382 { verbose_ = verbose; }
383
384 /*
385 * @}
386 */
387
388protected:
389 Dune::Timer timer_;
390 Scalar time_;
391 Scalar endTime_;
392
400};
401
406template <class Scalar>
407class CheckPointTimeLoop : public TimeLoop<Scalar>
408{
409public:
410 CheckPointTimeLoop(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose = true)
411 : TimeLoop<Scalar>(startTime, dt, tEnd, verbose)
412 {
413 periodicCheckPoints_ = false;
414 deltaPeriodicCheckPoint_ = 0.0;
415 lastPeriodicCheckPoint_ = startTime;
416 isCheckPoint_ = false;
417 }
418
422 void advanceTimeStep() override
423 {
424 const auto dt = this->timeStepSize();
425 const auto newTime = this->time()+dt;
426
428 // if we reached a periodic check point
429 if (periodicCheckPoints_ && Dune::FloatCmp::eq(newTime - lastPeriodicCheckPoint_, deltaPeriodicCheckPoint_, 1e-7))
430 {
431 lastPeriodicCheckPoint_ += deltaPeriodicCheckPoint_;
432 isCheckPoint_ = true;
433 }
434
435 // or a manually set check point
436 else if (!checkPoints_.empty() && Dune::FloatCmp::eq(newTime - checkPoints_.front(), 0.0, 1e-7))
437 {
438 checkPoints_.pop();
439 isCheckPoint_ = true;
440 }
441
442 // if not reset the check point flag
443 else
444 {
445 isCheckPoint_ = false;
446 }
447
448 const auto previousTimeStepSize = this->previousTimeStepSize();
449
450 // advance the time step like in the parent class
452
453 // if this is a check point we might have reduced the time step to reach this check point
454 // reset the time step size to the time step size before this time step
455 if (!this->willBeFinished())
456 {
457 using std::max;
458 if (isCheckPoint_)
460
461 // if there is a check point soon check if the time step after the next time step would be smaller
462 // than 20% of the next time step, if yes increase the suggested next time step to exactly reach the check point
463 // (in the limits of the maximum time step size)
464 auto nextDt = this->timeStepSize();
465 const auto threshold = 0.2*nextDt;
466 const auto nextTime = this->time() + nextDt;
467
468 if (periodicCheckPoints_ && Dune::FloatCmp::le(lastPeriodicCheckPoint_ + deltaPeriodicCheckPoint_ - nextTime, threshold))
469 nextDt = lastPeriodicCheckPoint_ + deltaPeriodicCheckPoint_ - this->time();
470
471 if (!checkPoints_.empty() && Dune::FloatCmp::le(checkPoints_.front() - nextTime, threshold))
472 nextDt = checkPoints_.front() - this->time();
473
474 assert(nextDt > 0.0);
475 this->setTimeStepSize(nextDt);
476 }
477 }
478
484 Scalar maxTimeStepSize() const override
485 {
486 using std::min;
487 const auto maxCheckPointDt = computeStepSizeRespectingCheckPoints_();
488 const auto maxDtParent = TimeLoop<Scalar>::maxTimeStepSize();
489 return min(maxDtParent, maxCheckPointDt);
490 }
491
502 void setPeriodicCheckPoint(Scalar interval, Scalar offset = 0.0)
503 {
504 using std::signbit;
505 if (signbit(interval))
506 DUNE_THROW(Dune::InvalidStateException, "Interval has to be positive!");
507
508 periodicCheckPoints_ = true;
509 deltaPeriodicCheckPoint_ = interval;
510 lastPeriodicCheckPoint_ = offset;
511 while (lastPeriodicCheckPoint_ + interval - this->time() < 1e-14*interval)
512 lastPeriodicCheckPoint_ += interval;
513
514 if (this->verbose())
515 std::cout << Fmt::format("Enabled periodic check points every {:.5g} seconds ", interval)
516 << Fmt::format("with the next check point at {:.5g} seconds.\n", lastPeriodicCheckPoint_ + interval);
517
518 // check if the current time point is a check point
519 if (Dune::FloatCmp::eq(this->time()-lastPeriodicCheckPoint_, 0.0, 1e-7))
520 isCheckPoint_ = true;
521
522 // make sure we respect this check point on the next time step
523 this->setTimeStepSize(this->timeStepSize());
524 }
525
528 { periodicCheckPoints_ = false; }
529
532 {
533 periodicCheckPoints_ = false;
534 while (!checkPoints_.empty())
535 checkPoints_.pop();
536 }
537
542 bool isCheckPoint() const
543 { return isCheckPoint_; }
544
551 void setCheckPoint(Scalar t)
552 {
553 // set the check point
554 setCheckPoint_(t);
555
556 // make sure we respect this check point on the next time step
557 this->setTimeStepSize(this->timeStepSize());
558 }
559
566 void setCheckPoint(const std::vector<Scalar>& checkPoints)
567 { setCheckPoint(checkPoints.begin(), checkPoints.end()); }
568
576 template<class ForwardIterator>
577 void setCheckPoint(ForwardIterator first, ForwardIterator last)
578 {
579 // set the check points
580 for (; first != last; ++first)
581 setCheckPoint_(*first);
582
583 // make sure we respect this check point on the next time step
584 this->setTimeStepSize(this->timeStepSize());
585 }
586
587private:
589 void setCheckPoint_(Scalar t)
590 {
591 if (Dune::FloatCmp::le(t - this->time(), 0.0, this->timeStepSize()*1e-7))
592 {
593 if (this->verbose())
594 std::cerr << Fmt::format("Couldn't insert checkpoint at t = {:.5g} ", t)
595 << Fmt::format("because that's in the past! (current simulation time is {:.5g})\n", this->time());
596 return;
597 }
598
599 if (!checkPoints_.empty())
600 {
601 if (t < checkPoints_.back())
602 {
603 if (this->verbose())
604 std::cerr << "Couldn't insert checkpoint as it is earlier than the last check point in the queue.\n"
605 << "Checkpoints can only be inserted in ascending order." << std::endl;
606 return;
607 }
608 }
609
610 checkPoints_.push(t);
611 if (this->verbose())
612 std::cout << Fmt::format("Set check point at t = {:.5g} seconds.\n", t);
613 }
614
618 Scalar computeStepSizeRespectingCheckPoints_() const
619 {
620 using std::min;
621 auto maxDt = std::numeric_limits<Scalar>::max();
622
623 if (periodicCheckPoints_)
624 maxDt = min(maxDt, lastPeriodicCheckPoint_ + deltaPeriodicCheckPoint_ - this->time());
625
626 if (!checkPoints_.empty())
627 maxDt = min(maxDt, checkPoints_.front() - this->time());
628
629 return maxDt;
630 }
631
632 bool periodicCheckPoints_;
633 Scalar deltaPeriodicCheckPoint_;
634 Scalar lastPeriodicCheckPoint_;
635 std::queue<Scalar> checkPoints_;
636 bool isCheckPoint_;
637};
638
639} // end namespace Dumux
640
641#endif
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Formatting based on the fmt-library which implements std::format of C++20.
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
Manages the handling of time dependent problems.
Definition: common/timeloop.hh:68
virtual ~TimeLoopBase()
Abstract base class needs virtual constructor.
Definition: common/timeloop.hh:71
virtual void setTimeStepSize(Scalar dt)=0
Set the current time step size to a given value.
virtual Scalar time() const =0
Return the time before the time integration. To get the time after the time integration you have to ...
virtual Scalar timeStepSize() const =0
Returns the suggested time step length .
virtual bool finished() const =0
Returns true if the simulation is finished.
virtual void advanceTimeStep()=0
Advance to the next time step.
virtual Scalar maxTimeStepSize() const =0
Get the maximum possible time step size .
The default time loop for instationary simulations.
Definition: common/timeloop.hh:113
Scalar maxTimeStepSize() const override
The current maximum time step size.
Definition: common/timeloop.hh:332
void setMaxTimeStepSize(Scalar maxDt)
Set the maximum time step size to a given value.
Definition: common/timeloop.hh:270
void resetTimer()
Reset the timer.
Definition: common/timeloop.hh:146
TimeLoop(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose=true)
Definition: common/timeloop.hh:115
void setVerbose(bool verbose=true)
Sets time loop verbosity.
Definition: common/timeloop.hh:381
void setTime(Scalar t, int stepIdx)
Set the current simulated time and the time step index.
Definition: common/timeloop.hh:210
Scalar time_
Definition: common/timeloop.hh:390
int timeStepIndex() const
Returns number of time steps which have been executed since the beginning of the simulation.
Definition: common/timeloop.hh:288
double stop()
Tells the time loop to stop tracking the time.
Definition: common/timeloop.hh:138
Scalar endTime_
Definition: common/timeloop.hh:391
Scalar previousTimeStepSize_
Definition: common/timeloop.hh:394
void advanceTimeStep() override
Advance time step.
Definition: common/timeloop.hh:180
int timeStepIdx_
Definition: common/timeloop.hh:397
void start()
Tells the time loop to start tracking the time.
Definition: common/timeloop.hh:129
Scalar userSetMaxTimeStepSize_
Definition: common/timeloop.hh:395
void setFinished(bool finished=true)
Specify whether the simulation is finished.
Definition: common/timeloop.hh:304
bool verbose() const
If the time loop has verbose output.
Definition: common/timeloop.hh:377
void finalize(const Communicator &comm=Dune::MPIHelper::getCommunication())
Print final status and stops tracking the time.
Definition: common/timeloop.hh:362
bool verbose_
Definition: common/timeloop.hh:399
bool willBeFinished() const
Returns true if the simulation is finished after the time level is incremented by the current time st...
Definition: common/timeloop.hh:322
Scalar previousTimeStepSize() const
The previous time step size.
Definition: common/timeloop.hh:294
void reset(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose=true)
Reset the time loop.
Definition: common/timeloop.hh:154
Scalar endTime() const
Returns the number of (simulated) seconds which the simulation runs.
Definition: common/timeloop.hh:224
void setTimeStepSize(Scalar dt) final
Set the current time step size to a given value.
Definition: common/timeloop.hh:255
bool finished() const override
Returns true if the simulation is finished.
Definition: common/timeloop.hh:313
Scalar timeStepSize_
Definition: common/timeloop.hh:393
void reportTimeStep() const
State info on cpu time.
Definition: common/timeloop.hh:345
Scalar timeStepSize() const final
Returns the suggested time step length so that we don't miss the beginning of the next episode or cr...
Definition: common/timeloop.hh:281
bool finished_
Definition: common/timeloop.hh:398
Dune::Timer timer_
Definition: common/timeloop.hh:389
void setTime(Scalar t)
Set the current simulated time, don't change the current time step index.
Definition: common/timeloop.hh:201
void setEndTime(Scalar t)
Set the time of simulated seconds at which the simulation runs.
Definition: common/timeloop.hh:232
double wallClockTime() const
Returns the current wall clock time (cpu time) spend in this time loop.
Definition: common/timeloop.hh:242
Scalar timeAfterLastTimeStep_
Definition: common/timeloop.hh:396
Scalar time() const final
Return the time before the time integration. To get the time after the time integration you have to ...
Definition: common/timeloop.hh:218
Scalar timeStepWallClockTime_
Definition: common/timeloop.hh:396
A time loop with a check point mechanism.
Definition: common/timeloop.hh:408
bool isCheckPoint() const
Whether now is a time checkpoint.
Definition: common/timeloop.hh:542
void setPeriodicCheckPoint(Scalar interval, Scalar offset=0.0)
Set a periodic check point.
Definition: common/timeloop.hh:502
void setCheckPoint(Scalar t)
add a checkpoint to the queue
Definition: common/timeloop.hh:551
void advanceTimeStep() override
Advance time step.
Definition: common/timeloop.hh:422
void removeAllCheckPoints()
remove all check points
Definition: common/timeloop.hh:531
void setCheckPoint(const std::vector< Scalar > &checkPoints)
add checkpoints to the queue from a vector of time points
Definition: common/timeloop.hh:566
Scalar maxTimeStepSize() const override
The current maximum time step size.
Definition: common/timeloop.hh:484
void setCheckPoint(ForwardIterator first, ForwardIterator last)
add checkpoints to the queue from a container from the first iterator to the last iterator
Definition: common/timeloop.hh:577
CheckPointTimeLoop(Scalar startTime, Scalar dt, Scalar tEnd, bool verbose=true)
Definition: common/timeloop.hh:410
void disablePeriodicCheckPoints()
disable periodic check points
Definition: common/timeloop.hh:527