Flow123d  jenkins-Flow123d-windows32-release-multijob-51
time_governor.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: time_governor.cc 1877 2012-09-27 12:53:36Z jan.brezina $
21  * $Revision: 1877 $
22  * $LastChangedBy: jan.brezina $
23  * $LastChangedDate: 2012-09-27 14:53:36 +0200 (Čt, 27 zář 2012) $
24  *
25  * @file
26  * @ingroup application
27  * @brief Basic time management class.
28  */
29 
30 #include "system/system.hh"
31 #include "time_governor.hh"
32 #include "time_marks.hh"
33 #include "input/accessors.hh"
34 
35 #include <limits>
36 
37 //initialize constant pointer to TimeMarks object
39 
41 const double TimeGovernor::inf_time = numeric_limits<double>::infinity();
42 const double TimeGovernor::round_n_steps_precision = 1e-14;
43 
44 
45 
46 using namespace Input::Type;
47 
48 
49 
50 
51 
52 Record TimeGovernor::input_type = Record("TimeGovernor",
53  "Setting of the simulation time. (can be specific to one equation)")
54  .allow_auto_conversion("init_dt")
55  .declare_key("start_time", Double(), Default("0.0"),
56  "Start time of the simulation.")
57  .declare_key("end_time", Double(), Default::read_time("Infinite end time."),
58  "End time of the simulation.")
59  .declare_key("init_dt", Double(0.0), Default("0.0"),
60  "Initial guess for the time step.\n"
61  "The time step is fixed if the hard time step limits are not set.\n"
62  "If set to 0.0, the time step is determined in fully autonomous way if the equation supports it.")
63  .declare_key("min_dt", Double(0.0), Default::read_time("Machine precision or 'init_dt' if specified"),
64  "Hard lower limit for the time step.")
65  .declare_key("max_dt", Double(0.0), Default::read_time("Whole time of the simulation or 'init_dt' if specified"),
66  "Hard upper limit for the time step.");
67 
68 
69 
70 
72 {
73  // use new mark type as default
74  if (eq_mark_type == TimeMark::none_type) eq_mark_type = marks().new_mark_type();
75 
76  try {
77  init_common(input.val<double>("init_dt"),
78  input.val<double>("start_time"),
79  input.val<double>("end_time", inf_time),
80  eq_mark_type);
81 
82  // possibly overwrite limits
83  set_permanent_constraint(
84  input.val<double>("min_dt", min_time_step_),
85  input.val<double>("max_dt", max_time_step_)
86  );
87  } catch(ExcTimeGovernorMessage &exc) {
88  exc << input.ei_address();
89  throw;
90  }
91 
92 }
93 
94 TimeGovernor::TimeGovernor(double init_time, double dt)
95 {
96  init_common(dt, init_time, inf_time, TimeMark::none_type);
97 }
98 
99 
100 // steady time governor constructor
101 TimeGovernor::TimeGovernor(double init_time, TimeMark::Type eq_mark_type)
102 {
103  // use new mark type as default
104  if (eq_mark_type == TimeMark::none_type) eq_mark_type = marks().new_mark_type();
105 
106  init_common(0.0, init_time, inf_time, eq_mark_type);
107  steady_ = true;
108 }
109 
110 
111 
112 // common part of constructors
113 void TimeGovernor::init_common(double dt, double init_time, double end_time, TimeMark::Type type)
114 {
115  time_level_=0;
116 
117  if (init_time < 0.0) {
118  THROW(ExcTimeGovernorMessage()
119  << EI_Message("Start time has to be greater or equal to 0.0\n")
120 
121  );
122  }
123 
124  init_time_ = time_ = init_time;
125  last_time_ = -inf_time;
126  last_time_step_ = inf_time;
127 
128 
129  if (end_time < init_time) {
130  THROW(ExcTimeGovernorMessage() << EI_Message("End time must be greater than start time.\n") );
131  }
132 
133  end_time_ = end_time;
134 
135  if (dt == 0.0) {
136  // variable time step
137  fixed_time_step_=0.0;
138  is_time_step_fixed_=false;
139  time_step_changed_=true;
140  end_of_fixed_dt_interval_ = time_;
141 
142  min_time_step_=lower_constraint_=time_step_lower_bound;
143  if (end_time_ == inf_time) {
144  max_time_step_=upper_constraint_=inf_time;
145  } else {
146  max_time_step_=upper_constraint_= end_time - time_;
147  }
148  // choose maximum possible time step
149  time_step_=max_time_step_;
150  } else {
151  // fixed time step
152  if (dt < time_step_lower_bound)
153  THROW(ExcTimeGovernorMessage() << EI_Message("Fixed time step small then machine precision. \n") );
154 
155  fixed_time_step_=dt;
156  is_time_step_fixed_=true;
157  time_step_changed_=true;
158  end_of_fixed_dt_interval_ = inf_time;
159 
160  upper_constraint_=max_time_step_=dt;
161  lower_constraint_=min_time_step_=dt;
162  time_step_=dt;
163 
164  }
165 
166  eq_mark_type_=type;
167  steady_=false;
168  time_marks_.add( TimeMark(time_, equation_fixed_mark_type()) );
169  if (end_time_ != inf_time)
170  time_marks_.add( TimeMark(end_time_, equation_fixed_mark_type()) );
171 }
172 
173 
174 
175 
176 
177 
178 void TimeGovernor::set_permanent_constraint( double min_dt, double max_dt)
179 {
180  if (min_dt < time_step_lower_bound) {
181  THROW(ExcTimeGovernorMessage() << EI_Message("'min_dt' smaller then machine precision.\n") );
182  }
183  if (max_dt < min_dt) {
184  THROW(ExcTimeGovernorMessage() << EI_Message("'max_dt' smaller then 'min_dt'.\n") );
185  }
186 
187  lower_constraint_ = min_time_step_ = max(min_dt, time_step_lower_bound);
188  upper_constraint_ = max_time_step_ = min(max_dt, end_time_-time_);
189 }
190 
191 
192 // int set_constrain - dle nastaveni constraint
193 // interval - constraint - jako v cmp u Qsortu
194 // -1 vetsi nez interval (min_dt,max_dt)
195 // +1 mensi
196 // 0 OK
197 
199 {
200  if (upper_constraint_ < upper)
201  {
202  //do not change upper_constraint_
203  return -1;
204  }
205 
206  if (lower_constraint_ <= upper)
207  {
208  //change upper_constraint_ to upper
209  upper_constraint_ = upper;
210  return 0;
211  }
212 
213  if (lower_constraint_ > upper)
214  {
215  //do not change upper_constraint_
216  return 1;
217  }
218 
219  return 0;
220 }
221 
223 {
224  if (upper_constraint_ < lower)
225  {
226  //do not change lower_constraint_
227  return -1;
228  }
229 
230  if (min_time_step_ <= lower)
231  {
232  //change lower_constraint_ to lower
233  lower_constraint_ = lower;
234  return 0;
235  }
236 
237  if (min_time_step_ > lower)
238  {
239  //do not change lower_constraint_
240  return 1;
241  }
242 
243  return 0;
244 }
245 
246 
247 
248 void TimeGovernor::add_time_marks_grid(double step, TimeMark::Type mark_type) const
249 {
250  if (end_time() == inf_time) {
251  THROW(ExcTimeGovernorMessage()
252  << EI_Message("Missing end time for making output grid required by key 'time_step' of the output stream.\n")
253  );
254  }
255 
256  marks().add_time_marks(init_time_, step, end_time(), mark_type | eq_mark_type_);
257  // always add start time and end time
258  marks().add(TimeMark(init_time_, mark_type | eq_mark_type_));
259  marks().add(TimeMark(end_time(), mark_type | eq_mark_type_));
260 }
261 
262 
263 
265  if (is_end()) return 0.0;
266 
267  if (this->lt(end_of_fixed_dt_interval_)) return fixed_time_step_;
268 
269  // jump to the first future fix time
270  TimeMarks::iterator fix_time_it = time_marks_.next(*this, equation_fixed_mark_type());
271  // compute step to next fix time and apply constraints
272  double full_step = fix_time_it->time() - time_;
273 
274  double step_estimate = min(full_step, upper_constraint_);
275  step_estimate = max(step_estimate, lower_constraint_); //these two must be in this order
276 
277  if (step_estimate == inf_time) return step_estimate;
278 
279  // round the time step to have integer number of steps till next fix time
280  // this always selects shorter time step
281  int n_steps = ceil( full_step / step_estimate );
282 
283 
284  //checking rounding precision: e.g. 1.0000000000000009 -> 1 NOT 2
285  int n_floor_steps = floor(full_step / step_estimate);
286  if ( abs(full_step / step_estimate - n_floor_steps) < round_n_steps_precision) n_steps = n_floor_steps;
287 
288  step_estimate = full_step / n_steps;
289 
290  // if the step estimate gets by rounding lower than lower constraint program will not crash
291  // will just output a user warning.
292  if (step_estimate < lower_constraint_)
293  xprintf(Warn, "Time step estimate is below the lower constraint of time step. The difference is: %.16f.\n",
294  lower_constraint_ - step_estimate);
295 
296  return step_estimate;
297 }
298 
299 
300 
302 {
303  ASSERT_LE(0.0, time_);
304  if (is_end()) return;
305 
306  if (this->lt(end_of_fixed_dt_interval_)) {
307  // this is done for fixed step
308  // make tiny correction of time step in order to avoid big rounding errors
309  // tiny correction means that dt_changed 'is NOT changed'
310  if (end_of_fixed_dt_interval_ < inf_time) {
311  fixed_time_step_ = (end_of_fixed_dt_interval_-time_) / round( (end_of_fixed_dt_interval_-time_) / fixed_time_step_ );
312  }
313 
314  last_time_step_ = time_step_;
315  time_step_ = fixed_time_step_;
316 
317  //checking whether fixed time step has been changed (by fix_dt_until_mark() method) since last time
318  if (is_time_step_fixed_)
319  {
320  is_time_step_fixed_ = false;
321 
322  //is true unless new fixed_dt is not equal previous time_step
323  time_step_changed_ = (last_time_step_ != time_step_);
324  }
325  else
326  time_step_changed_ = false;
327  }
328  else
329  {
330  // this is done if end_of_fixed_dt_interval is not set (means it is equal to -infinity)
331  last_time_step_ = time_step_;
332  time_step_ = estimate_dt();
333  time_step_changed_= (last_time_step_ != time_step_);
334  }
335 
336  last_time_ = time_;
337  time_+=time_step_;
338  time_level_++;
339  // refreshing the upper_constraint_
340  upper_constraint_ = min(end_time_ - time_, max_time_step_);
341  lower_constraint_ = min_time_step_;
342 
343 }
344 
345 
346 
347 void TimeGovernor::view(const char *name) const
348 {
349  xprintf(Msg, "\nTG[%s]:%06d t:%10.4f dt:%10.6f dt_int<%10.6f,%10.6f>",
350  name, time_level_, time_, time_step_, lower_constraint_, upper_constraint_ );
351 #ifdef DEBUG_MESSAGES
352  xprintf(Msg, " end_time: %f end_fixed_time: %f type: 0x%x\n" , end_time_, end_of_fixed_dt_interval_, eq_mark_type_);
353 #else
354  xprintf(Msg,"\n");
355 #endif
356 }
357 
358 
359 ostream& operator<<(ostream& out, const TimeGovernor& tg)
360 {
361  static char buffer[1024];
362  sprintf(buffer, "\n%06d t:%10.4f dt:%10.6f dt_int<%10.6f,%10.6f>\n",
363  tg.tlevel(), tg.t(), tg.dt(), tg.lower_constraint(), tg.upper_constraint());
364  return (out << buffer);
365 }
366 
367 
unsigned long int Type
Definition: time_marks.hh:59
void init_common(double dt, double init_time, double end_time, TimeMark::Type type)
Common part of the constructors. Set most important parameters, check they are valid and set default ...
static const double round_n_steps_precision
Rounding precision for computing number of steps. Used in estimate_dt().
Iterator over TimeMark objects in TimeMarks object (database of TimeMark objects).
Definition: time_marks.hh:283
Definition: system.hh:72
int tlevel() const
static TimeMarks time_marks_
double upper_constraint() const
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
TimeGovernor(const Input::Record &input, TimeMark::Type fixed_time_mask=TimeMark::none_type)
Constructor for unsteady solvers.
void set_permanent_constraint(double min_dt, double max_dt)
Sets permanent constraints for time step.
void next_time()
Proceed to the next time according to current estimated time step.
double t() const
Basic time management functionality for unsteady (and steady) solvers (class Equation).
static const Type none_type
Mask that matches no type of TimeMark.
Definition: time_marks.hh:64
Basic time management class.
double estimate_dt() const
Estimate choice of next time step according to actual setting of constraints.
void view(const char *name="") const
EI_Address ei_address() const
Definition: accessors.cc:185
Record & allow_auto_conversion(const string &from_key)
Definition: type_record.cc:83
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:376
Definition: system.hh:72
void add_time_marks_grid(double step, TimeMark::Type mark_type=TimeMark::none_type) const
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:100
int set_lower_constraint(double lower)
Sets lower constraint for the next time step estimating.
double lower_constraint() const
static Input::Type::Record input_type
This class is a collection of time marks to manage various events occurring during simulation time...
Definition: time_marks.hh:165
#define ASSERT_LE(a, b)
Definition: global_defs.h:165
static Default read_time(const std::string &description)
Definition: type_record.hh:75
const double epsilon
Definition: mathfce.h:6
int set_upper_constraint(double upper)
Sets upper constraint for the next time step estimating.
double dt() const
static const double time_step_lower_bound
Technical bound for the time step given by finite precision.
double time() const
Getter for the time of the TimeMark.
Definition: time_marks.hh:84
std::ostream & operator<<(std::ostream &stream, const TypeBase &type)
Definition: type_base.cc:128
Class used for marking specified times at which some events occur.
Definition: time_marks.hh:44
Record type proxy class.
Definition: type_record.hh:161
static const double inf_time
Infinity time used for steady case.
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:34
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:386