Flow123d  release_2.2.0-914-gf1a3a4f
time_governor.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file time_governor.hh
15  * @brief Basic time management class.
16  * @author Jan Brezina
17  */
18 
19 #ifndef TIME_HH_
20 #define TIME_HH_
21 
22 #include <boost/circular_buffer.hpp>
23 #include <boost/exception/info.hpp>
24 #include <iosfwd>
25 #include <string>
26 
27 #include "input/input_exception.hh"
28 #include "system/exc_common.hh"
29 #include "system/exceptions.hh"
30 #include "tools/time_marks.hh"
31 
32 namespace Input {
33  class Record;
34  namespace Type {
35  class Record;
36  }
37 }
38 
39 
40 
41 
42 /**
43  * @brief Representation of one time step.\
44  *
45  * Time step consists of the time step @p length() and from time step @end() time.
46  * More over we store the index of the time step within it time governor.
47  *
48  * The reason to store both the end time and the length of the time step is to allow
49  * safe comparisons of the time with safety margin small relative to the
50  * time step length.
51  */
52 class TimeStep {
53 public:
54  /**
55  * Constructor of the zero time step.
56  */
57  TimeStep(double init_time);
58 
59  /**
60  * Default constructor.
61  * Creates undefined time step.
62  */
63  TimeStep();
64 
65  /**
66  * Copy constructor.
67  */
68  TimeStep(const TimeStep &other);
69 
70  /**
71  * Create subsequent time step.
72  */
73  TimeStep make_next(double new_length) const;
74 
75  /**
76  * Create subsequent time step, with the @end_time
77  * explicitly specified. This allow slight discrepancy to
78  * overcome rounding errors in the case of fixed time step.
79  * Otherwise using small fixed time step, we may miss long term fixed
80  * goal time.
81  *
82  */
83  TimeStep make_next(double new_lenght, double end_time) const;
84 
85  /**
86  * Getters.
87  */
88  unsigned int index() const {return index_;}
89  double length() const { return length_;}
90  double end() const { return end_;}
91  /**
92  * Performs rounding safe comparison time > other_time, i.e. time is strictly greater than given parameter
93  * other_time with precision relative to the magnitude of the numbers time step.
94  * TODO: introduce type TimeDouble with overloaded comparison operators, use it consistently in TimeMarks.
95  */
96  inline bool gt(double other_time) const
97  { return ! safe_compare(other_time, end());}
98 
99  /**
100  * Performs rounding safe comparison time >= other_time See @fn gt
101  */
102  inline bool ge(double other_time) const
103  { return safe_compare(end(), other_time); }
104 
105  /**
106  * Performs rounding safe comparison time < other_time. See @fn gt
107  */
108  inline bool lt(double other_time) const
109  { return ! safe_compare(end(), other_time); }
110 
111  /**
112  * Performs rounding safe comparison time <= other_time. See @fn gt
113  */
114  inline bool le(double other_time) const
115  { return safe_compare(other_time, end()); }
116 
117  /**
118  * Performs rounding safe comparison time (step) == other_time. See @fn gt
119  */
120  inline bool eq(double other_time) const
121  { return this->le(other_time) && this->ge(other_time); }
122 
123  inline bool contains(double other_time) const
124  { return this->ge(other_time) && this->lt(other_time + length_); }
125 
126  /**
127  * Returns true if two time steps are exactly the same.
128  */
129  bool operator==(const TimeStep & other)
130  { return (index_ == other.index_)
131  && (length_ == other.length_)
132  && (end_ == other.end_);
133  }
134 private:
135 
136  /* Returns true if t1-t0 > delta. Where delta is choosen
137  * related to the current time step and magnitude of t1, t0.
138  */
139  bool safe_compare(double t1, double t0) const;
140 
141  /// Index of the step is index if the end time. Zero time step is artificial.
142  unsigned int index_;
143  /// Length of the time step. Theoretically @p end minus end of the previous time step.
144  /// However may be slightly different due to rounding errors.
145  double length_;
146  /// End time point of the time step.
147  double end_;
148 };
149 
150 std::ostream& operator<<(std::ostream& out, const TimeStep& t_step);
151 
152 
153 
154 /**
155  * @brief
156  * Basic time management functionality for unsteady (and steady) solvers (class Equation).
157  *
158  * <h2> Common features and unsteady time governor (TG) </h2>
159  *
160  * This class provides algorithm for selecting next time step, and information about current time step frame.
161  * Step estimating is constrained by several bounds (permanent maximal and minimal time step, upper
162  * and lower constraint of time step). The permanent constraints are set in the constructor from the input
163  * record so that user can set the time step constraints for the whole simulation.
164  * Function set_permanent_constraint() should be used only in very specific cases and possibly right after
165  * the constructor before using other functions of TG.
166  *
167  * Choice of the very next time step can be constrained using functions set_upper_constraint()
168  * and set_lower_constraint().
169  * Lower and upper constraints are set equal to permanent ones in the constructor and can only
170  * become stricter. If one tries to set these constraints outside the interval of the previous constraints,
171  * nothing is changed and a specified value is returned. Upper and lower constraints are reset in function
172  * next_time() to the permanent constraints.
173  *
174  * The later one can be called multiple times with various constraint values and we use the minimum of them.
175  * Function next_time() choose the next time step in such a way that it meets actual constraints and
176  * a uniform discrete time grid with this step hits the nearest fixed time in lowest possible number of steps.
177  *
178  * The fixed times are time marks of TimeMarks object passed at construction time with particular mask.
179  *
180  * There is just one set of time marks for the whole problem. Therefore TimeMarks object is static and is shared umong
181  * all the equations and time governors. Each equation creates its own specific time mark type.
182  *
183  * Information provided by TG includes:
184  * - actual time, last time, end time
185  * - actual time step
186  * - number of the time level
187  * - end of interval with fixed time step
188  * - time comparison
189  * - static pointer to time marks
190  *
191  * <h2> Steady time governor</h2>
192  *
193  * Steady TG can be constructed by default constructor (initial time is zero) or by
194  * constructor with initial time as parameter. End time and time step are set to infinity.
195  * One can check if the time governor is steady by calling is_steady().
196  * Calling estimate_dt() will return infinity.
197  *
198  * Setting constraints have no consequences. Calling fix_dt_until_mark() will only return zero
199  * and will not do anything.
200  *
201  * The steady TG works in two states. At first the time is set to initial and time level
202  * is equal zero. To use steady TG properly one should call next_time() after the computation
203  * of steady problem is done. Current time is then set to infinity, time level is set to 1 and
204  * calling estimate_dt() will return zero.
205  *
206  * Note: For example class TransportNothing (which computes really nothing) uses also steady TG but
207  * it calls next_time() immediately after TG's construction. This means that the 'computation'of transport
208  * is done.
209  *
210  *
211  */
212 
214 {
215 public:
216 
217  DECLARE_INPUT_EXCEPTION(ExcTimeGovernorMessage, << EI_Message::val);
218  TYPEDEF_ERR_INFO( EI_Index, int);
219  TYPEDEF_ERR_INFO( EI_BackIndex, unsigned int);
220  TYPEDEF_ERR_INFO( EI_HistorySize, unsigned int);
221  DECLARE_EXCEPTION(ExcMissingTimeStep,
222  << "Time step index: " << EI_Index::val
223  << ", history index: " << EI_BackIndex::val
224  << " out of history of size: " << EI_HistorySize::val);
225 
226  static const Input::Type::Record & get_input_type();
227 
228  /**
229  * Getter for time marks.
230  */
231  static inline TimeMarks &marks()
232  {return time_marks_;}
233 
234  /**
235  * @brief Constructor for unsteady solvers.
236  *
237  * @param input accessor to input data
238  * @param fixed_time_mask TimeMark mask used to select fixed time marks from all the time marks.
239  * This value is bitwise added to the default one defined in TimeMarks::type_fixed_time().
240  *
241  */
242  TimeGovernor(const Input::Record &input,
243  TimeMark::Type fixed_time_mask = TimeMark::none_type);
244 
245  /**
246  * @brief Default constructor - steady time governor.
247  *
248  * OBSOLETE.
249  *
250  * We can have "zero step" steady problem (no computation, e.g. EquationNothing) and one step steady problem
251  * (e.g. steady water flow).
252  *
253  * Time is set to zero, time step and end time to infinity.
254  *
255  * First call of next_time() pushes the actual time to infinity.
256  *
257  * However, you have to use full constructor for the "steady problem" that has time-variable input data.
258  *
259  * Has a private pointer to static TimeMarks and can access them by marks().
260  */
261  explicit TimeGovernor(double init_time=0.0,
262  TimeMark::Type fixed_time_mask = TimeMark::none_type);
263 
264  /**
265  * The aim of this constuctor is simple way to make a time governor without Input interface.
266  *
267  * TODO: Partially tested as part of field test. Needs its own unit test.
268  */
269  TimeGovernor(double init_time, double dt);
270 
271  /**
272  * Returns true if the time governor was set from default values
273  */
274  bool is_default() {
275  return (end_time_ == max_end_time)
276  && (max_time_step_ == end_time_ - init_time_);
277  }
278 
279  /**
280  * @brief Sets permanent constraints for time step.
281  *
282  * This function should not be normally used. These values are to be set in constructor
283  * from the input record or by default.
284  * @param min_dt is the minimal value allowed for time step
285  * @param max_dt is the maximal value allowed for time step
286  */
287  void set_permanent_constraint( double min_dt, double max_dt);
288 
289  /**
290  * @brief Sets upper constraint for the next time step estimating.
291  *
292  * This function can only make the constraint stricter. Upper constraint is reset to @p max_dt after the next_time() call.
293  * The return value mimics result of the comparison: current constraint compared to @param upper.
294  * @param message describes the origin of the constraint
295  * In particular the return values is:
296  * - -1: Current upper constraint is less then the @param upper. No change happen.
297  * - 0: Current constraint interval contains the @param upper. The upper constraint is set.
298  * - +1: Current lower constraint is greater then the @param upper. No change happen.
299  */
300  int set_upper_constraint(double upper, std::string message);
301 
302  /**
303  * @brief Sets lower constraint for the next time step estimating.
304  *
305  * This function can only make the constraint stricter. Lower constraint is reset to @p min_dt after the next_time() call.
306  * The return value mimics result of the comparison: current constraint compared to @param upper.
307  * In particular the return values is:
308  * - -1: Current upper constraint is less then the @param lower. No change happen.
309  * - 0: Current constraint interval contains the @param lower. The lower constraint is set.
310  * - +1: Current upper constraint is greater then the @param lower. No change happen.
311  */
312  /**
313  * @brief Sets lower constraint for the next time step estimating.
314  * @param lower is the lower constraint for time step
315  * @param message describes the origin of the constraint
316  * @return -1, 0 or 1 according to the success.
317  * @see set_upper_constrain().
318  */
319  int set_lower_constraint(double lower, std::string message);
320 
321  /**
322  * @brief Fixing time step until fixed time mark.
323  *
324  * Fix time step until first fixed time mark. When called inside an already fixed interval,
325  * it overwrites previous setting.
326  * @return actual end of fixed time step.
327  */
328  double fix_dt_until_mark();
329 
330  /**
331  * @brief Proceed to the next time according to current estimated time step.
332  *
333  * The timestep constraints are relaxed to the permanent constraints.
334  */
335  void next_time();
336 
337  /**
338  * @brief Force timestep reduction in particular in the case of failure of the non-linear solver.
339  *
340  * Calling this method also force immediate end of the fixed timestep interval.
341  * Returns true reduce factor used. It is larger then given factor if we hit the lower timestep constraint.
342  *
343  * TODO: How to keep constraints active for the last next_time call.
344  */
345  double reduce_timestep(double factor);
346 
347  /**
348  * Returns reference to required time step in the recent history.
349  * Without parameter the actual time step is returned.
350  * Use negative indices to get recent time steps: step(-1) the actual step, step(-2) the last one.
351  * Use positive index to get time step by its index: step(0) the first time step.
352  * However only limited number of last time steps is stored.
353  * If the time step is not accessible any more, we throw an exception ExcMissingTimeStep.
354  */
355  const TimeStep &step(int index=-1) const;
356 
357  /**
358  * Specific time mark of the equation owning the time governor.
359  */
361  { return eq_mark_type_;}
362 
363  /**
364  * Specific time mark of the fixed times of the equation owning the time governor.
365  */
367  { return eq_mark_type_ | marks().type_fixed_time(); }
368 
369  /**
370  * Add sequence of time marks starting from the initial time up to the end time with given @p step.
371  * Time marks type combines given mark_type (none by default) and native mark type of the time governor.
372  */
373  void add_time_marks_grid(double step, TimeMark::Type mark_type= TimeMark::none_type) const;
374 
375  /**
376  * Simpler interface to TimeMarks::is_current().
377  */
378  bool is_current(const TimeMark::Type &mask) const;
379 
380 
381  /**
382  * Simpler interface to TimeMarks::next().
383  */
384  inline TimeMarks::iterator next(const TimeMark::Type &mask) const
385  {return time_marks_.next(*this, mask);}
386 
387  /**
388  * Simpler interface to TimeMarks::last().
389  */
390  inline TimeMarks::iterator last(const TimeMark::Type &mask) const
391  {return time_marks_.last(*this, mask);}
392 
393  /**
394  * Getter for upper constrain.
395  */
396  inline double upper_constraint() const
397  {return upper_constraint_;}
398 
399  /**
400  * Returns lower constraint.
401  */
402  inline double lower_constraint() const
403  {return lower_constraint_;}
404 
405  /**
406  * End of interval with currently fixed time step. Can be changed by next call of method fix_dt_until_mark.
407  */
408  inline double end_of_fixed_dt() const
409  {return end_of_fixed_dt_interval_;}
410 
411  /**
412  * Getter for dt_changed. Returns whether the time step has been changed.
413  */
414  inline bool is_changed_dt() const
415  {return time_step_changed_;}
416 
417 
418  /**
419  * Initial time getter.
420  */
421  inline double init_time() const
422  {return this->init_time_;}
423 
424  /**
425  * End of actual time interval; i.e. where the solution is computed.
426  */
427  inline double t() const
428  {return step().end();}
429 
430  /**
431  * Previous time step.
432  */
433  inline double last_dt() const
434  {if (step().index() >0) return step(-2).length();
435  else return inf_time;
436  }
437 
438  /**
439  * Previous time.
440  */
441  inline double last_t() const
442  {if (step().index() >0) return step(-2).end();
443  else return step().end() - step().length();
444  }
445 
446 
447  /**
448  * Length of actual time interval; i.e. the actual time step.
449  */
450  inline double dt() const
451  {return step().length();}
452 
453  /**
454  * @brief Estimate choice of next time step according to actual setting of constraints.
455  *
456  * Precedence of constraints:
457  *
458  * -# meet next fixed time (always satisfied)
459  * -# permanent upper constraint (always satisfied)
460  * -# upper constraint (always satisfied)
461  * -# lower constraint (satisfied if not in conflict with 1.)
462  * -# permanent lower constraint (satisfied if 4.)
463  * -# else writes the difference between lower constraint and estimated time step
464  * -# If there are more then one step to the next fixed time, try to
465  * use the last time step if it is nearly the same.
466  */
467  double estimate_dt() const;
468 
469  /**
470  * Estimate next time.
471  */
472  inline double estimate_time() const
473  {return t()+estimate_dt();}
474 
475  /// End time.
476  inline double end_time() const
477  { return end_time_; }
478 
479  /// Returns true if the actual time is greater than or equal to the end time.
480  inline bool is_end() const
481  { return (this->step().ge(end_time_) || t() == inf_time); }
482 
483  /// Returns true if the time governor is used for steady problem.
484  inline bool is_steady() const
485  { return steady_; }
486 
487 
488 
489  /**
490  * Returns the time level.
491  */
492  inline int tlevel() const
493  {return step().index();}
494 
495  /**
496  * Prints output of TimeGovernor.
497  * @param name is the name of time governor that you want to show up in output (just for your convenience)
498  *
499  */
500  void view(const char *name="") const;
501 
502  // Maximal tiem of simulation. More then age of the universe in seconds.
503  static const double max_end_time;
504 
505  /// Infinity time used for steady case.
506  static const double inf_time;
507 
508  /**
509  * Rounding precision for computing time_step.
510  * Used as technical lower bound for the time step.
511  */
512  static const double time_step_precision;
513 
514 private:
515 
516 
517  /**
518  * \brief Common part of the constructors. Set most important parameters, check they are valid and set default values to other.
519  *
520  * Set main parameters to given values.
521  * Check they are correct.
522  * Set soft and permanent constrains to the same, the least restricting values.
523  * Set time marks for the start time and end time (if finite).
524  */
525  void init_common(double init_time, double end_time, TimeMark::Type type);
526 
527  /**
528  * Size of the time step buffer, i.e. recent_time_steps_.
529  */
530  static const unsigned int size_of_recent_steps_ = 3;
531 
532  /// Circular buffer of recent time steps. Implicit size is 3.
533  boost::circular_buffer<TimeStep> recent_steps_;
534  /// Initial time.
535  double init_time_;
536  /// End of interval if fixed time step.
538  /// End time of the simulation.
539  double end_time_;
540 
541  /// Next fixed time step.
543  /// Flag that is set when the fixed step is set (lasts only one time step).
545  /// Flag is set if the time step has been changed (lasts only one time step).
547 
548  /// Description of the upper constraint.
550  /// Description of the upper constraint.
552  /// Upper constraint for the choice of the next time step.
554  /// Lower constraint for the choice of the next time step.
556  /// Permanent upper limit for the time step.
558  /// Permanent lower limit for the time step.
560 
561  /// Upper constraint used for choice of current time.
563  /// Lower constraint used for choice of current time.
565 
566  /**
567  * When the next time is chosen we need only the lowest fix time. Therefore we use
568  * minimum priority queue of doubles based on the vector container.
569  * This is one global set of time marks for the whole problem and is shared among all equations.
570  * Therefore this object is static constant pointer.
571  */
573 
574  /// TimeMark type of the equation.
576 
577  /// True if the time governor is used for steady problem.
578  bool steady_;
579 
580  friend TimeMarks;
581 };
582 
583 /**
584  * \brief Stream output operator for TimeGovernor.
585  *
586  * Currently for debugging purposes.
587  * In the future it should be customized for use in combination with
588  * streams for various log targets.
589  *
590  */
591 std::ostream& operator<<(std::ostream& out, const TimeGovernor& tg);
592 
593 
594 
595 #endif /* TIME_HH_ */
bool operator==(const TimeStep &other)
double init_time_
Initial time.
double lower_constraint_
Lower constraint for the choice of the next time step.
Iterator over TimeMark objects in TimeMarks object (database of TimeMark objects).
Definition: time_marks.hh:351
double end_time() const
End time.
double estimate_time() const
bool is_time_step_fixed_
Flag that is set when the fixed step is set (lasts only one time step).
boost::circular_buffer< TimeStep > recent_steps_
Circular buffer of recent time steps. Implicit size is 3.
int tlevel() const
static TimeMarks time_marks_
bool lt(double other_time) const
TYPEDEF_ERR_INFO(EI_KeyName, const string)
double upper_constraint() const
double end_time_
End time of the simulation.
bool contains(double other_time) const
Abstract linear system class.
Definition: equation.hh:37
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
TimeMarks::iterator last(const TimeMark::Type &mask) const
TimeMarks::iterator next(const TimeMark::Type &mask) const
double end_of_fixed_dt() const
static const double max_end_time
double t() const
Basic time management functionality for unsteady (and steady) solvers (class Equation).
static const Type none_type
Mark Type with all bits unset.
Definition: time_marks.hh:95
static TimeMarks & marks()
bool time_step_changed_
Flag is set if the time step has been changed (lasts only one time step).
double last_t() const
bool le(double other_time) const
double upper_constraint_
Upper constraint for the choice of the next time step.
double init_time() const
TimeMark::Type eq_mark_type_
TimeMark type of the equation.
bool ge(double other_time) const
static const double time_step_precision
TimeMark::Type equation_fixed_mark_type() const
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
TimeMark::Type equation_mark_type() const
bool is_changed_dt() const
double length() const
double last_lower_constraint_
Lower constraint used for choice of current time.
double lower_constraint() const
unsigned int index_
Index of the step is index if the end time. Zero time step is artificial.
double end() const
This class is a collection of time marks to manage various events occurring during simulation time...
Definition: time_marks.hh:206
double end_of_fixed_dt_interval_
End of interval if fixed time step.
bool steady_
True if the time governor is used for steady problem.
bool is_steady() const
Returns true if the time governor is used for steady problem.
double max_time_step_
Permanent upper limit for the time step.
double dt() const
std::string upper_constraint_message_
Description of the upper constraint.
bool gt(double other_time) const
DECLARE_EXCEPTION(ExcWrongDefaultJSON,<< "Consistency Error: Not valid JSON of Default value "<< EI_DefaultStr::qval<< " of type "<< EI_TypeName::qval<< ";\n"<< "During declaration of the key: "<< EI_KeyName::qval)
std::ostream & operator<<(std::ostream &stream, const TypeBase &type)
For convenience we provide also redirection operator for output documentation of Input:Type classes...
Definition: type_base.cc:240
unsigned int index() const
Record type proxy class.
Definition: type_record.hh:182
double length_
double fixed_time_step_
Next fixed time step.
DECLARE_INPUT_EXCEPTION(ExcInputMessage,<< EI_Message::val)
Simple input exception that accepts just string message.
double last_upper_constraint_
Upper constraint used for choice of current time.
double last_dt() const
static const double inf_time
Infinity time used for steady case.
Representation of one time step..
double end_
End time point of the time step.
std::string lower_constraint_message_
Description of the upper constraint.
bool eq(double other_time) const
double min_time_step_
Permanent lower limit for the time step.