simulator.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  Copyright (C) 2009-2013 by Andreas Lauser
5  Copyright (C) 2011-2012 by Markus Wolff
6  Copyright (C) 2011 by Benjamin Faigle
7 
8  This file is part of the Open Porous Media project (OPM).
9 
10  OPM is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 2 of the License, or
13  (at your option) any later version.
14 
15  OPM is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with OPM. If not, see <http://www.gnu.org/licenses/>.
22 */
28 #ifndef EWOMS_SIMULATOR_HH
29 #define EWOMS_SIMULATOR_HH
30 
31 #include <ewoms/io/restart.hh>
33 
35 #include <ewoms/common/timer.hh>
36 
37 #include <dune/common/version.hh>
38 #if DUNE_VERSION_NEWER(DUNE_COMMON, 2,3)
39 #include <dune/common/parallel/mpihelper.hh>
40 #else
41 #include <dune/common/mpihelper.hh>
42 #endif
43 
44 #include <iostream>
45 #include <iomanip>
46 #include <memory>
47 
48 namespace Ewoms {
49 namespace Properties {
50 NEW_PROP_TAG(Scalar);
51 NEW_PROP_TAG(GridManager);
52 NEW_PROP_TAG(GridView);
53 NEW_PROP_TAG(Model);
54 NEW_PROP_TAG(Problem);
55 NEW_PROP_TAG(EndTime);
56 NEW_PROP_TAG(RestartTime);
57 NEW_PROP_TAG(InitialTimeStepSize);
58 }
59 
72 template <class TypeTag>
73 class Simulator
74 {
75  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
76  typedef typename GET_PROP_TYPE(TypeTag, GridManager) GridManager;
77  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
78  typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
79  typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
80 
81 
82 public:
83  // do not allow to copy simulators around
84  Simulator(const Simulator &) = delete;
85 
86  Simulator(bool verbose = true)
87  {
88  setupTimer_.start();
89 
90  verbose_ = verbose && Dune::MPIHelper::getCollectiveCommunication().rank() == 0;
91 
92  timeStepIdx_ = 0;
93  startTime_ = 0.0;
94  time_ = 0.0;
95  endTime_ = EWOMS_GET_PARAM(TypeTag, Scalar, EndTime);
96  timeStepSize_ = EWOMS_GET_PARAM(TypeTag, Scalar, InitialTimeStepSize);
97 
98  episodeIdx_ = 0;
99  episodeStartTime_ = 0;
100  episodeLength_ = 1e100;
101 
102  finished_ = false;
103 
104  if (verbose_)
105  std::cout << "Allocating the grid\n" << std::flush;
106  gridManager_.reset(new GridManager(*this));
107 
108  if (verbose_)
109  std::cout << "Distributing the grid\n" << std::flush;
110  gridManager_->loadBalance();
111 
112  if (verbose_)
113  std::cout << "Allocating the model\n" << std::flush;
114  model_.reset(new Model(*this));
115 
116  if (verbose_)
117  std::cout << "Allocating the problem\n" << std::flush;
118  problem_.reset(new Problem(*this));
119 
120  if (verbose_)
121  std::cout << "Finish init of the model\n" << std::flush;
122  model_->finishInit();
123 
124  if (verbose_)
125  std::cout << "Finish init of the problem\n" << std::flush;
126  problem_->finishInit();
127 
128  if (verbose_)
129  std::cout << "Construction of simulation done\n" << std::flush;
130  }
131 
135  static void registerParameters()
136  {
137  EWOMS_REGISTER_PARAM(TypeTag, Scalar, EndTime,
138  "The simulation time at which the simulation is finished [s]");
139  EWOMS_REGISTER_PARAM(TypeTag, Scalar, InitialTimeStepSize,
140  "The size of the initial time step [s]");
141  EWOMS_REGISTER_PARAM(TypeTag, Scalar, RestartTime,
142  "The simulation time at which a restart should be attempted [s]");
143 
144  GridManager::registerParameters();
145  Model::registerParameters();
146  Problem::registerParameters();
147  }
148 
152  GridManager &gridManager()
153  { return *gridManager_; }
154 
158  const GridManager &gridManager() const
159  { return *gridManager_; }
160 
164  GridView &gridView()
165  { return gridManager_->gridView(); }
166 
170  const GridView &gridView() const
171  { return gridManager_->gridView(); }
172 
176  Model &model()
177  { return *model_; }
178 
182  const Model &model() const
183  { return *model_; }
184 
189  Problem &problem()
190  { return *problem_; }
191 
196  const Problem &problem() const
197  { return *problem_; }
198 
204  void setStartTime(Scalar t)
205  { startTime_ = t; }
206 
210  Scalar startTime() const
211  { return startTime_; }
212 
219  void setTime(Scalar t)
220  { time_ = t; }
221 
228  void setTime(Scalar t, int stepIdx)
229  {
230  time_ = t;
231  timeStepIdx_ = stepIdx;
232  }
233 
241  Scalar time() const
242  { return time_; }
243 
249  void setEndTime(Scalar t)
250  { endTime_ = t; }
251 
256  Scalar endTime() const
257  { return endTime_; }
258 
262  const Ewoms::Timer& timer() const
263  { return executionTimer_; }
264 
269  Scalar totalWriteTime() const
270  { return totalWriteTime_; }
271 
275  double setupTime() const
276  { return setupTimer_.realTimeElapsed(); }
277 
289  { timeStepSize_ = timeStepSize; }
290 
296  Scalar timeStepSize() const
297  {
298  Scalar maximumTimeStepSize =
299  std::min(episodeMaxTimeStepSize(),
300  std::max<Scalar>(0.0, endTime() - this->time()));
301 
302  return std::min(timeStepSize_, maximumTimeStepSize);
303  }
304 
309  int timeStepIndex() const
310  { return timeStepIdx_; }
311 
319  void setFinished(bool yesno = true)
320  { finished_ = yesno; }
321 
328  bool finished() const
329  {
330  assert(timeStepSize_ >= 0.0);
331  Scalar eps = std::max(std::abs(this->time()), timeStepSize())*1e-8;
332  return finished_ || (this->time() + eps >= endTime());
333  }
334 
339  bool willBeFinished() const
340  {
341  return
342  finished_ ||
343  (this->time() + std::max(std::abs(this->time()), timeStepSize())*1e-8 + timeStepSize_
344  >= endTime());
345  }
346 
351  Scalar maxTimeStepSize() const
352  {
353  if (finished())
354  return 0.0;
355 
356  return std::min(episodeMaxTimeStepSize(),
357  std::max<Scalar>(0.0, endTime() - this->time()));
358  }
359 
367  {
368  ++episodeIdx_;
369  episodeStartTime_ = episodeStartTime;
370  episodeLength_ = episodeLength;
371  }
372 
380  void startNextEpisode(Scalar len = 1e100)
381  {
382  ++episodeIdx_;
383  episodeStartTime_ = startTime_ + time_;
384  episodeLength_ = len;
385  }
386 
392  void setEpisodeIndex(int episodeIdx)
393  { episodeIdx_ = episodeIdx; }
394 
400  int episodeIndex() const
401  { return episodeIdx_; }
402 
407  Scalar episodeStartTime() const
408  { return episodeStartTime_; }
409 
414  Scalar episodeLength() const
415  { return episodeLength_; }
416 
421  bool episodeIsOver() const
422  { return startTime() + this->time() > episodeStartTime_ + episodeLength()*(1 - 1e-8); }
423 
428  bool episodeWillBeOver() const
429  {
430  return startTime() + this->time() + timeStepSize()
431  >= episodeStartTime_ + episodeLength()*(1 - 1e-8);
432  }
433 
438  Scalar episodeMaxTimeStepSize() const
439  {
440  // if the current episode is over and the simulation
441  // wants to give it some extra time, we will return
442  // the time step size it suggested instead of trying
443  // to align it to the end of the episode.
444  if (episodeIsOver())
445  return 0.0;
446 
447  // make sure that we don't exceed the end of the
448  // current episode.
449  return std::max<Scalar>(0.0,
451  - (this->time() + this->startTime()));
452  }
453 
454  /*
455  * \}
456  */
457 
464  void run()
465  {
466  Scalar restartTime = EWOMS_GET_PARAM(TypeTag, Scalar, RestartTime);
467  if (restartTime > -1e100) {
468  // try to restart a previous simulation
469  time_ = restartTime;
470 
471  Ewoms::Restart res;
472  res.deserializeBegin(*this, time_);
473  if (verbose_)
474  std::cout << "Deserialize from file '" << res.fileName() << "'\n" << std::flush;
475  this->deserialize(res);
476  problem_->deserialize(res);
477  model_->deserialize(res);
478  res.deserializeEnd();
479  if (verbose_)
480  std::cout << "Deserialization done."
481  << " Simulator time: " << time() << humanReadableTime(time())
482  << " Time step index: " << timeStepIndex()
483  << " Episode index: " << episodeIndex()
484  << "\n" << std::flush;
485  }
486  else {
487  // if no restart is done, apply the initial solution
488  if (verbose_)
489  std::cout << "Applying the initial solution of the \"" << problem_->name()
490  << "\" problem\n" << std::flush;
491 
492  Scalar oldTimeStepSize = timeStepSize_;
493  int oldTimeStepIdx = timeStepIdx_;
494  timeStepSize_ = 0.0;
495  timeStepIdx_ = -1;
496 
497  model_->applyInitialSolution();
498 
499  // write initial condition
500  if (problem_->shouldWriteOutput())
501  problem_->writeOutput();
502 
503  timeStepSize_ = oldTimeStepSize;
504  timeStepIdx_ = oldTimeStepIdx;
505  }
506 
507  setupTimer_.stop();
508 
509  totalWriteTime_ = 0.0;
510  executionTimer_.start();
511 
512  prePostProcessTime_ = 0;
513  Timer prePostProcessTimer;
514  bool episodeBegins = episodeIsOver() || (timeStepIdx_ == 0);
515  // do the time steps
516  while (!finished()) {
517  prePostProcessTimer.start();
518  if (episodeBegins) {
519  // notify the problem that a new episode has just been
520  // started.
521  problem_->beginEpisode();
522 
523  if (finished()) {
524  // the problem can chose to terminate the simulation in
525  // beginEpisode(), so we have handle this case.
526  problem_->endEpisode();
527  prePostProcessTimer.stop();
528  prePostProcessTime_ += prePostProcessTimer.realTimeElapsed();
529  break;
530  }
531  }
532  episodeBegins = false;
533 
534  if (verbose_) {
535  std::cout << "Begin time step " << timeStepIndex() << ". "
536  << "Start time: " << this->time() << " seconds" << humanReadableTime(this->time())
537  << ", step size: " << timeStepSize() << " seconds" << humanReadableTime(timeStepSize())
538  << "\n";
539  }
540 
541  // pre-process the current solution
542  problem_->beginTimeStep();
543  if (finished()) {
544  // the problem can chose to terminate the simulation in
545  // beginTimeStep(), so we have handle this case.
546  problem_->endTimeStep();
547  problem_->endEpisode();
548  prePostProcessTimer.stop();
549  prePostProcessTime_ += prePostProcessTimer.realTimeElapsed();
550  break;
551  }
552  prePostProcessTimer.stop();
553  prePostProcessTime_ += prePostProcessTimer.realTimeElapsed();
554 
555  // execute the time integration scheme
556  problem_->timeIntegration();
557 
558  // post-process the current solution
559  prePostProcessTimer.start();
560  problem_->endTimeStep();
561  prePostProcessTimer.stop();
562  prePostProcessTime_ += prePostProcessTimer.realTimeElapsed();
563 
564  // write the result to disk
565  writeTimer_.start();
566  if (problem_->shouldWriteOutput())
567  problem_->writeOutput();
568  writeTimer_.stop();
569  totalWriteTime_ += writeTimer_.realTimeElapsed();
570 
571  // do the next time integration
572  Scalar oldDt = timeStepSize();
573  problem_->advanceTimeLevel();
574 
575  // advance the simulated time by the current time step size
576  time_ += oldDt;
577  ++timeStepIdx_;
578 
579  if (verbose_) {
580  std::cout << "Time step " << timeStepIndex() << " done. "
581  << "CPU time: " << executionTimer_.realTimeElapsed() << " seconds" << humanReadableTime(executionTimer_.realTimeElapsed())
582  << ", end time: " << this->time() << " seconds" << humanReadableTime(this->time())
583  << ", step size: " << oldDt << " seconds" << humanReadableTime(oldDt)
584  << "\n" << std::flush;
585  }
586 
587  prePostProcessTimer.start();
588  // notify the problem if an episode is finished
589  if (episodeIsOver()) {
590  // make the linearization not usable for the first iteration of the next
591  // time step at the end of each episode. Strictly speaking, this is a
592  // layering violation as the simulator is not supposed to know any
593  // specifics of the non-linear solver, but this call is too easy to
594  // forget within the problem's endEpisode(), so we do it here anyway!
595  model_->linearizer().setLinearizationReusable(false);
596 
597  // Notify the problem about the end of the current episode...
598  problem_->endEpisode();
599  episodeBegins = true;
600  }
601  else
602  // ask the problem to provide the next time step size
603  setTimeStepSize(problem_->nextTimeStepSize());
604  prePostProcessTimer.stop();
605  prePostProcessTime_ += prePostProcessTimer.realTimeElapsed();
606 
607  // write restart file if mandated by the problem
608  writeTimer_.start();
609  if (problem_->shouldWriteRestartFile())
610  serialize();
611  writeTimer_.stop();
612  totalWriteTime_ += writeTimer_.realTimeElapsed();
613  }
614 
615  executionTimer_.stop();
616 
617  problem_->finalize();
618  }
619 
620  Scalar prePostProcessTime() const
621  { return prePostProcessTime_; }
622 
623  void addPrePostProcessTime(Scalar value)
624  { prePostProcessTime_ += value; }
625 
632  static std::string humanReadableTime(Scalar timeInSeconds, bool isAmendment=true)
633  {
634  std::ostringstream oss;
635  oss << std::setprecision(4);
636  if (isAmendment)
637  oss << " (";
638  if (timeInSeconds >= 365.25*24*60*60) {
639  int years = timeInSeconds/(365.25*24*60*60);
640  int days = (timeInSeconds - years*(365.25*24*60*60))/(24*60*60);
641  double hours = (timeInSeconds - years*(365.25*24*60*60) - days*(24*60*60))/(60*60);
642  oss << years << " years, " << days << " days, " << hours << " hours";
643  }
644  else if (timeInSeconds >= 24.0*60*60) {
645  int days = timeInSeconds/(24*60*60);
646  int hours = (timeInSeconds - days*(24*60*60))/(60*60);
647  double minutes = (timeInSeconds - days*(24*60*60) - hours*(60*60))/60;
648  oss << days << " days, " << hours << " hours, " << minutes << " minutes";
649  }
650  else if (timeInSeconds >= 60.0*60) {
651  int hours = timeInSeconds/(60*60);
652  int minutes = (timeInSeconds - hours*(60*60))/60;
653  double seconds = (timeInSeconds - hours*(60*60) - minutes*60);
654  oss << hours << " hours, " << minutes << " minutes, " << seconds << " seconds";
655  }
656  else if (timeInSeconds >= 60.0) {
657  int minutes = timeInSeconds/60;
658  double seconds = (timeInSeconds - minutes*60);
659  oss << minutes << " minutes, " << seconds << " seconds";
660  }
661  else if (!isAmendment)
662  oss << timeInSeconds << " seconds";
663  else
664  return "";
665  if (isAmendment)
666  oss << ")";
667 
668  return oss.str();
669  }
670 
685  void serialize()
686  {
687  typedef Ewoms::Restart Restarter;
688  Restarter res;
689  res.serializeBegin(*this);
690  if (gridView().comm().rank() == 0)
691  std::cout << "Serialize to file '" << res.fileName() << "'"
692  << ", next time step size: " << timeStepSize()
693  << "\n" << std::flush;
694 
695  this->serialize(res);
696  problem_->serialize(res);
697  model_->serialize(res);
698  res.serializeEnd();
699  }
700 
708  template <class Restarter>
709  void serialize(Restarter &restarter)
710  {
711  restarter.serializeSectionBegin("Simulator");
712  restarter.serializeStream()
713  << episodeIdx_ << " "
714  << episodeStartTime_ << " "
715  << episodeLength_ << " "
716  << startTime_ << " "
717  << time_ << " "
718  << timeStepIdx_ << " ";
719  restarter.serializeSectionEnd();
720  }
721 
729  template <class Restarter>
730  void deserialize(Restarter &restarter)
731  {
732  restarter.deserializeSectionBegin("Simulator");
733  restarter.deserializeStream()
734  >> episodeIdx_
735  >> episodeStartTime_
736  >> episodeLength_
737  >> startTime_
738  >> time_
739  >> timeStepIdx_;
740  restarter.deserializeSectionEnd();
741  }
742 
743 private:
744  std::unique_ptr<GridManager> gridManager_;
745  std::unique_ptr<Model> model_;
746  std::unique_ptr<Problem> problem_;
747 
748  int episodeIdx_;
749  Scalar episodeStartTime_;
750  Scalar episodeLength_;
751 
752  Ewoms::Timer setupTimer_;
753  Ewoms::Timer executionTimer_;
754  Ewoms::Timer writeTimer_;
755  Scalar totalWriteTime_;
756  Scalar startTime_;
757  Scalar prePostProcessTime_;
758  Scalar time_;
759  Scalar endTime_;
760 
761  Scalar timeStepSize_;
762  int timeStepIdx_;
763  bool finished_;
764  bool verbose_;
765 };
766 } // namespace Ewoms
767 
768 #endif
Load or save a state of a problem to/from the harddisk.
bool episodeIsOver() const
Returns true if the current episode is finished at the current time.
Definition: simulator.hh:421
void deserializeBegin(Simulator &simulator, double t)
Start reading a restart file at a certain simulated time.
Definition: restart.hh:165
Scalar timeStepSize() const
Returns the time step length so that we don't miss the beginning of the next episode or cross the en...
Definition: simulator.hh:296
Scalar prePostProcessTime() const
Definition: simulator.hh:620
Problem & problem()
Return the object which specifies the pysical setup of the simulation.
Definition: simulator.hh:189
const Ewoms::Timer & timer() const
Returns the current wall time required by actually running the simulation.
Definition: simulator.hh:262
void serializeBegin(Simulator &simulator)
Write the current state of the model to disk.
Definition: restart.hh:95
const GridManager & gridManager() const
Return a reference to the grid manager of simulation.
Definition: simulator.hh:158
Simulator(bool verbose=true)
Definition: simulator.hh:86
const std::string & fileName() const
Returns the name of the file which is (de-)serialized.
Definition: restart.hh:88
Scalar startTime() const
Return the time of the start of the simulation.
Definition: simulator.hh:210
Scalar endTime() const
Returns the number of (simulated) seconds which the simulation runs.
Definition: simulator.hh:256
bool finished() const
Returns true if the simulation is finished.
Definition: simulator.hh:328
void setStartTime(Scalar t)
Set the time of the start of the simulation.
Definition: simulator.hh:204
void serialize()
This method writes the complete state of the simulation to the harddisk.
Definition: simulator.hh:685
void addPrePostProcessTime(Scalar value)
Definition: simulator.hh:623
bool episodeWillBeOver() const
Returns true if the current episode will be finished after the current time step. ...
Definition: simulator.hh:428
void startNextEpisode(Scalar len=1e100)
Start the next episode, but don't change the episode identifier.
Definition: simulator.hh:380
Load or save a state of a problem to/from the harddisk.
Definition: restart.hh:41
GridManager & gridManager()
Return a reference to the grid manager of simulation.
Definition: simulator.hh:152
void setTime(Scalar t, int stepIdx)
Set the current simulated time and the time step index.
Definition: simulator.hh:228
void deserialize(Restarter &restarter)
Read the time manager's state from a restart file.
Definition: simulator.hh:730
Provides an encapsulation to measure the system time.
static void registerParameters()
Registers all runtime parameters used by the simulation.
Definition: simulator.hh:135
NEW_PROP_TAG(Grid)
The type of the DUNE grid.
void setEndTime(Scalar t)
Set the time of simulated seconds at which the simulation runs.
Definition: simulator.hh:249
This file provides the infrastructure to retrieve run-time parameters.
int timeStepIndex() const
Returns number of time steps which have been executed since the beginning of the simulation.
Definition: simulator.hh:309
const Problem & problem() const
Return the object which specifies the pysical setup of the simulation.
Definition: simulator.hh:196
void setTimeStepSize(Scalar timeStepSize)
Set the current time step size to a given value.
Definition: simulator.hh:288
void setEpisodeIndex(int episodeIdx)
Sets the index of the current episode.
Definition: simulator.hh:392
Scalar totalWriteTime() const
Returns total wall clock time required to write the visualization and restart files over the course o...
Definition: simulator.hh:269
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:73
Scalar episodeLength() const
Returns the length of the current episode in simulated time .
Definition: simulator.hh:414
Definition: baseauxiliarymodule.hh:35
Scalar maxTimeStepSize() const
Aligns the time step size to the episode boundary and to the end time of the simulation.
Definition: simulator.hh:351
#define EWOMS_REGISTER_PARAM(TypeTag, ParamType, ParamName, Description)
Register a run-time parameter.
Definition: parametersystem.hh:64
void serialize(Restarter &restarter)
Write the time manager's state to a restart file.
Definition: simulator.hh:709
void setFinished(bool yesno=true)
Specify whether the simulation is finished.
Definition: simulator.hh:319
Model & model()
Return the physical model used in the simulation.
Definition: simulator.hh:176
const Model & model() const
Return the physical model used in the simulation.
Definition: simulator.hh:182
static std::string humanReadableTime(Scalar timeInSeconds, bool isAmendment=true)
Given a time step size in seconds, return it in a format which is more easily parsable by humans...
Definition: simulator.hh:632
void deserializeEnd()
Stop reading the restart file.
Definition: restart.hh:263
Scalar time() const
Return the number of seconds of simulated time which have elapsed since the start time...
Definition: simulator.hh:241
GridView & gridView()
Return the grid view for which the simulation is done.
Definition: simulator.hh:164
void run()
Runs the simulation using a given problem class.
Definition: simulator.hh:464
const GridView & gridView() const
Return the grid view for which the simulation is done.
Definition: simulator.hh:170
Provides the magic behind the eWoms property system.
Scalar episodeMaxTimeStepSize() const
Aligns the time step size to the episode boundary if the current time step crosses the boundary of th...
Definition: simulator.hh:438
double realTimeElapsed() const
Return the real time [s] elapsed.
Definition: timer.hh:100
Provides an encapsulation to measure the system time.
Definition: timer.hh:47
bool willBeFinished() const
Returns true if the simulation is finished after the time level is incremented by the current time st...
Definition: simulator.hh:339
int episodeIndex() const
Returns the index of the current episode.
Definition: simulator.hh:400
double setupTime() const
Returns the wall time required by setting up and initializing the simulation.
Definition: simulator.hh:275
Simulator(const Simulator &)=delete
void start()
Start counting the time resources used by the simulation.
Definition: timer.hh:68
void startNextEpisode(Scalar episodeStartTime, Scalar episodeLength)
Change the current episode of the simulation.
Definition: simulator.hh:366
void setTime(Scalar t)
Set the current simulated time, don't change the current time step index.
Definition: simulator.hh:219
Scalar episodeStartTime() const
Returns the absolute time when the current episode started .
Definition: simulator.hh:407
#define EWOMS_GET_PARAM(TypeTag, ParamType, ParamName)
Retrieve a runtime parameter.
Definition: parametersystem.hh:95
void stop()
Stop counting the time resources used by the simulation.
Definition: timer.hh:77