Flow123d  jenkins-Flow123d-windows-release-multijob-285
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 
31 #include <limits>
32 #include "system/system.hh"
33 #include "input/accessors.hh"
34 #include "time_governor.hh"
35 #include "time_marks.hh"
36 
37 //initialize constant pointer to TimeMarks object
39 
40 //const double TimeGovernor::time_step_lower_bound = numeric_limits<double>::epsilon();
41 const double TimeGovernor::inf_time = numeric_limits<double>::infinity();
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("max_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  "Only useful for equations that use adaptive time stepping."
62  "If set to 0.0, the time step is determined in fully autonomous"
63  " way if the equation supports it.")
64  .declare_key("min_dt", Double(0.0),
65  Default::read_time("Machine precision."),
66  "Soft lower limit for the time step. Equation using adaptive time stepping can not"
67  "suggest smaller time step, but actual time step could be smaller in order to match "
68  "prescribed input or output times.")
69  .declare_key("max_dt", Double(0.0),
70  Default::read_time("Whole time of the simulation if specified, infinity else."),
71  "Hard upper limit for the time step. Actual length of the time step is also limited"
72  "by input and output times.");
73 
74 
75 
76 TimeStep::TimeStep(double init_time) :
77 index_(0),
78 length_(1.0),
79 end_(init_time)
80 {}
81 
82 
83 
85 index_(0),
86 length_(TimeGovernor::inf_time),
87 end_(-TimeGovernor::inf_time)
88 {}
89 
90 
91 
92 
94 index_(other.index_),
95 length_(other.length_),
96 end_(other.end_)
97 {}
98 
99 
100 
101 TimeStep TimeStep::make_next(double new_length) const
102 {
103  return make_next(new_length, this->end_+new_length);
104 }
105 
106 
107 
108 TimeStep TimeStep::make_next(double new_lenght, double end_time) const
109 {
110  TimeStep ts;
111  ts.index_=this->index_ +1;
112  ts.length_=new_lenght;
113  ts.end_=end_time;
114  return ts;
115 }
116 
117 
118 
119 bool TimeStep::safe_compare(double t1, double t0) const
120 {
121  return t1 >= t0
122  - 16*numeric_limits<double>::epsilon()*(1.0+max(abs(t1),abs(t0)));
123 }
124 
125 
126 
128 {
129  // use new mark type as default
130  if (eq_mark_type == TimeMark::none_type) eq_mark_type = marks().new_mark_type();
131 
132  try {
133  // set permanent limits
134  init_common(input.val<double>("start_time"),
135  input.val<double>("end_time", inf_time),
136  eq_mark_type);
138  input.val<double>("min_dt", min_time_step_),
139  input.val<double>("max_dt", max_time_step_)
140  );
141 
142  double init_dt=input.val<double>("init_dt");
143  if (init_dt > 0.0) {
144  // set first time step suggested by user
145  //time_step_=min(init_dt, time_step_);
146  lower_constraint_=init_dt;
147  upper_constraint_=init_dt;
148  } else {
149  // apply constraints
150  //time_step_=min(time_step_, upper_constraint_);
151  //time_step_=max(time_step_, lower_constraint_);
152  }
153 
154 
155  } catch(ExcTimeGovernorMessage &exc) {
156  exc << input.ei_address();
157  throw;
158  }
159 
160 }
161 
162 TimeGovernor::TimeGovernor(double init_time, double dt)
163 {
165  // fixed time step
166  if (dt < time_step_precision)
167  THROW(ExcTimeGovernorMessage() << EI_Message("Fixed time step smaller then machine precision. \n") );
168 
170  is_time_step_fixed_=true;
171  time_step_changed_=true;
173 
176  //time_step_=dt;
177 }
178 
179 
180 // steady time governor constructor
181 TimeGovernor::TimeGovernor(double init_time, TimeMark::Type eq_mark_type)
182 {
183  // use new mark type as default
184  if (eq_mark_type == TimeMark::none_type) eq_mark_type = marks().new_mark_type();
185 
186  init_common(init_time, inf_time, eq_mark_type);
187  steady_ = true;
188 }
189 
190 
191 
192 // common part of constructors
193 void TimeGovernor::init_common(double init_time, double end_time, TimeMark::Type type)
194 {
195 
196 
197  if (init_time < 0.0) {
198  THROW(ExcTimeGovernorMessage()
199  << EI_Message("Start time has to be greater or equal to 0.0\n")
200 
201  );
202  }
203 
204  recent_steps_.set_capacity(2);
205  recent_steps_.push_front(TimeStep(init_time));
207 
208  if (end_time < init_time) {
209  THROW(ExcTimeGovernorMessage() << EI_Message("End time must be greater than start time.\n") );
210  } else {
212  }
213 
214  //if (dt == 0.0) {
215  // variable time step
216  fixed_time_step_=0.0;
217  is_time_step_fixed_=false;
218  time_step_changed_=true;
220 
222  if (end_time_ == inf_time) {
224  } else {
226  }
227  // choose maximum possible time step
228  //time_step_=max_time_step_;
229  /*} else {
230  // fixed time step
231  if (dt < time_step_lower_bound)
232  THROW(ExcTimeGovernorMessage() << EI_Message("Fixed time step smaller then machine precision. \n") );
233 
234  fixed_time_step_=dt;
235  is_time_step_fixed_=true;
236  time_step_changed_=true;
237  end_of_fixed_dt_interval_ = inf_time;
238 
239  upper_constraint_=max_time_step_=dt;
240  lower_constraint_=min_time_step_=dt;
241  time_step_=dt;
242 
243  }*/
244 
245  eq_mark_type_=type;
246  steady_=false;
248  if (end_time_ != inf_time)
250 }
251 
252 
253 
254 
255 
256 
257 void TimeGovernor::set_permanent_constraint( double min_dt, double max_dt)
258 {
259  if (min_dt < time_step_precision) {
260  THROW(ExcTimeGovernorMessage() << EI_Message("'min_dt' smaller then machine precision.\n") );
261  }
262  if (max_dt < min_dt) {
263  THROW(ExcTimeGovernorMessage() << EI_Message("'max_dt' smaller then 'min_dt'.\n") );
264  }
265 
267  upper_constraint_ = max_time_step_ = min(max_dt, end_time_-t());
268 }
269 
270 
271 // int set_constrain - dle nastaveni constraint
272 // interval - constraint - jako v cmp u Qsortu
273 // -1 vetsi nez interval (min_dt,max_dt)
274 // +1 mensi
275 // 0 OK
276 
278 {
279  if (upper_constraint_ < upper)
280  {
281  //do not change upper_constraint_
282  return -1;
283  }
284 
285  if (lower_constraint_ <= upper)
286  {
287  //change upper_constraint_ to upper
288  upper_constraint_ = upper;
289  return 0;
290  }
291 
292  if (lower_constraint_ > upper)
293  {
294  //do not change upper_constraint_
295  return 1;
296  }
297 
298  return 0;
299 }
300 
301 
302 
304 {
305  if (upper_constraint_ < lower)
306  {
307  //do not change lower_constraint_
308  return -1;
309  }
310 
311  if (min_time_step_ <= lower)
312  {
313  //change lower_constraint_ to lower
314  lower_constraint_ = lower;
315  return 0;
316  }
317 
318  if (min_time_step_ > lower)
319  {
320  //do not change lower_constraint_
321  return 1;
322  }
323 
324  return 0;
325 }
326 
327 
328 
329 
331  if (steady_) return 0.0;
332  end_of_fixed_dt_interval_=-inf_time; // release previous fixed interval
334  is_time_step_fixed_ = true; //flag means fixed step has been set since now
336 }
337 
338 
339 
340 
341 void TimeGovernor::add_time_marks_grid(double step, TimeMark::Type mark_type) const
342 {
343  if (end_time() == inf_time) {
344  THROW(ExcTimeGovernorMessage()
345  << EI_Message("Missing end time for making output grid required by key 'time_step' of the output stream.\n")
346  );
347  }
348 
349  marks().add_time_marks(init_time_, step, end_time(), mark_type | eq_mark_type_);
350  // always add start time and end time
351  marks().add(TimeMark(init_time_, mark_type | eq_mark_type_));
352  marks().add(TimeMark(end_time(), mark_type | eq_mark_type_));
353 }
354 
355 
356 
358  if (is_end()) return 0.0;
359 
360  if (this->step().lt(end_of_fixed_dt_interval_)) return fixed_time_step_;
361 
362  // jump to the first future fix time
364  // compute step to next fix time and apply constraints
365  double full_step = fix_time_it->time() - t();
366 
367  double step_estimate = min(full_step, upper_constraint_);
368  step_estimate = max(step_estimate, lower_constraint_); //these two must be in this order
369 
370  if (step_estimate == inf_time) return step_estimate;
371 
372  // round the time step to have integer number of steps till next fix time
373  // this always selects shorter time step,
374  // but allows time step larger then constraint by a number close to machine epsilon
375  //
376  int n_steps = ceil( full_step / step_estimate - time_step_precision);
377  step_estimate = full_step / n_steps;
378 
379  // try to avoid time_step changes
380  if (n_steps > 1 && abs(step_estimate - step().length()) < time_step_precision) {
381  step_estimate=step().length();
382  }
383 
384  // if the step estimate gets by rounding lower than lower constraint program will not crash
385  // will just output a user warning.
386  if (step_estimate < lower_constraint_)
387  xprintf(Warn, "Time step estimate is below the lower constraint of time step. The difference is: %.16f.\n",
388  lower_constraint_ - step_estimate);
389 
390  return step_estimate;
391 }
392 
393 
394 
396 {
397  ASSERT_LE(0.0, t());
398  if (is_end()) return;
399 
400 
401  if (this->step().lt(end_of_fixed_dt_interval_)) {
402  // this is done for fixed step
403  // make tiny correction of time step in order to avoid big rounding errors
404  // tiny correction means that dt_changed 'is NOT changed'
407  }
408 
409  recent_steps_.push_front(recent_steps_.front().make_next(fixed_time_step_));
410 
411 
412  //checking whether fixed time step has been changed (by fix_dt_until_mark() method) since last time
414  {
415  is_time_step_fixed_ = false;
416 
417  //is true unless new fixed_dt is not equal previous time_step
418  time_step_changed_ = (step(-2).length() != step().length());
419  }
420  else
421  time_step_changed_ = false;
422  }
423  else
424  {
425  // this is done if end_of_fixed_dt_interval is not set (means it is equal to -infinity)
426  double dt=estimate_dt();
427  TimeStep step_ = recent_steps_.front().make_next(dt);
428  //DBGMSG("step: %f, end: %f\n", step_.length(), step_.end());
429  recent_steps_.push_front(step_);
430  //DBGMSG("last:%f, new: %f\n",step(-1).length(),step().length());
431  time_step_changed_= (step(-2).length() != step().length());
432  }
433 
434  // refreshing the upper_constraint_
437 
438 }
439 
440 
441 
442 const TimeStep &TimeGovernor::step(int index) const {
443  unsigned int back_idx;
444  if (index < 0) {
445  back_idx = static_cast<unsigned int>(-index-1);
446  } else {
447  back_idx = static_cast<unsigned int>(recent_steps_[0].index() - index);
448  }
449  if ( back_idx >= recent_steps_.size())
450  THROW(ExcMissingTimeStep() << EI_Index(index) << EI_BackIndex(back_idx) << EI_HistorySize(recent_steps_.size()));
451 
452  return recent_steps_[back_idx];
453 }
454 
455 
456 
457 
458 void TimeGovernor::view(const char *name) const
459 {
460  xprintf(Msg, "\nTG[%s]:%06d t:%10.4f dt:%10.6f dt_int<%10.6f,%10.6f>",
461  name, tlevel(), t(), dt(), lower_constraint_, upper_constraint_ );
462 #ifdef DEBUG_MESSAGES
463  xprintf(Msg, " end_time: %f end_fixed_time: %f type: 0x%x\n" , end_time_, end_of_fixed_dt_interval_, eq_mark_type_);
464 #else
465  xprintf(Msg,"\n");
466 #endif
467 }
468 
469 
470 
471 
472 ostream& operator<<(ostream& out, const TimeGovernor& tg)
473 {
474  static char buffer[1024];
475  sprintf(buffer, "\n%06d t:%10.4f dt:%10.6f dt_int<%10.6f,%10.6f>\n",
476  tg.tlevel(), tg.t(), tg.dt(), tg.lower_constraint(), tg.upper_constraint());
477  return (out << buffer);
478 }
479 
480 
void add_time_marks(double time, double dt, double end_time, TimeMark::Type type)
Definition: time_marks.cc:111
unsigned long int Type
Definition: time_marks.hh:64
double init_time_
Initial time.
TimeMarks::iterator next(const TimeGovernor &tg, const TimeMark::Type &mask) const
Definition: time_marks.cc:130
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:294
double end_time() const
End time.
bool is_time_step_fixed_
Flag that is set when the fixed step is set (lasts only one time step).
Definition: system.hh:72
boost::circular_buffer< TimeStep > recent_steps_
Circular buffer of recent time steps. Implicit size is 2.
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.
double end_time_
End time of the simulation.
double fix_dt_until_mark()
Fixing time step until fixed time mark.
void set_permanent_constraint(double min_dt, double max_dt)
Sets permanent constraints for time step.
bool is_end() const
Returns true if the actual time is greater than or equal to the end time.
void next_time()
Proceed to the next time according to current estimated time step.
const TimeStep & step(int index=-1) const
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:69
static TimeMarks & marks()
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
bool time_step_changed_
Flag is set if the time step has been changed (lasts only one time step).
EI_Address ei_address() const
Definition: accessors.cc:187
void add(const TimeMark &mark)
Definition: time_marks.cc:88
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.
Record & allow_auto_conversion(const string &from_key)
Definition: type_record.cc:111
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:392
Definition: system.hh:72
void add_time_marks_grid(double step, TimeMark::Type mark_type=TimeMark::none_type) 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:327
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.
TimeMark::Type new_mark_type()
Definition: time_marks.cc:80
double length() const
double lower_constraint() const
static Input::Type::Record input_type
unsigned int index_
Index of the step is index if the end time. Zero time step is artificial.
ostream & operator<<(ostream &out, const TimeGovernor &tg)
Stream output operator for TimeGovernor.
This class is a collection of time marks to manage various events occurring during simulation time...
Definition: time_marks.hh:170
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.
TimeStep make_next(double new_length) const
#define ASSERT_LE(a, b)
Definition: global_defs.h:165
double max_time_step_
Permanent upper limit for the time step.
static Default read_time(const std::string &description)
Definition: type_record.hh:77
const double epsilon
Definition: mathfce.h:6
void init_common(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 ...
bool safe_compare(double t1, double t0) const
int set_upper_constraint(double upper)
Sets upper constraint for the next time step estimating.
double dt() const
double time() const
Getter for the time of the TimeMark.
Definition: time_marks.hh:89
Class used for marking specified times at which some events occur.
Definition: time_marks.hh:49
Record type proxy class.
Definition: type_record.hh:169
double length_
double fixed_time_step_
Next fixed time step.
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
Representation of one time step.
double end_
End time point of the time step.
double min_time_step_
Permanent lower limit for the time step.
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:430