Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_TimeEventRange_impl.hpp
Go to the documentation of this file.
1 //@HEADER
2 // *****************************************************************************
3 // Tempus: Time Integration and Sensitivity Analysis Package
4 //
5 // Copyright 2017 NTESS and the Tempus contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 //@HEADER
9 
10 #ifndef Tempus_TimeEventRange_impl_hpp
11 #define Tempus_TimeEventRange_impl_hpp
12 
14 
15 namespace Tempus {
16 
17 template <class Scalar>
19  : start_(0.0),
20  stop_(0.0),
21  stride_(0.0),
22  numEvents_(1),
23  timeScale_(1.0),
24  relTol_(this->getDefaultTol()),
25  absTol_(this->getDefaultTol()),
26  landOnExactly_(true)
27 {
28  this->setType("Range");
29  setRelTol(this->getDefaultTol()), setTimeRange(0.0, 0.0, 0.0);
30  setLandOnExactly(true);
31  std::ostringstream oss;
32  oss << "TimeEventRange (" << start_ << "; " << stop_ << "; " << stride_
33  << ")";
34  this->setName(oss.str());
35 }
36 
37 template <class Scalar>
38 TimeEventRange<Scalar>::TimeEventRange(Scalar start, Scalar stop, Scalar stride,
39  std::string name, bool landOnExactly,
40  Scalar relTol)
41  : start_(start),
42  stop_(stop),
43  stride_(stride),
44  numEvents_(0),
45  timeScale_(std::max(std::abs(start_), std::abs(stop_))),
46  relTol_(relTol),
47  absTol_(relTol_ * timeScale_),
48  landOnExactly_(landOnExactly)
49 {
50  this->setType("Range");
51  if (name == "") {
52  std::ostringstream oss;
53  oss << "TimeEventRange (" << start << "; " << stop << "; " << stride << ")";
54  this->setName(oss.str());
55  }
56  else {
57  this->setName(name);
58  }
59  setRelTol(relTol);
60  setTimeRange(start, stop, stride);
61  setLandOnExactly(landOnExactly);
62 }
63 
64 template <class Scalar>
65 TimeEventRange<Scalar>::TimeEventRange(Scalar start, Scalar stop, int numEvents,
66  std::string name, bool landOnExactly,
67  Scalar relTol)
68  : start_(start),
69  stop_(stop),
70  stride_(0.0),
71  numEvents_(numEvents),
72  timeScale_(std::max(std::abs(start_), std::abs(stop_))),
73  relTol_(relTol),
74  absTol_(relTol_ * timeScale_),
75  landOnExactly_(landOnExactly)
76 {
77  if (name == "") {
78  std::ostringstream oss;
79  oss << "TimeEventRange (" << start << "; " << stop << "; " << numEvents
80  << ")";
81  this->setName(oss.str());
82  }
83  else {
84  this->setName(name);
85  }
86  setRelTol(relTol);
87  setTimeRange(start, stop, numEvents);
88  setLandOnExactly(landOnExactly);
89 }
90 
91 template <class Scalar>
92 void TimeEventRange<Scalar>::setTimeRange(Scalar start, Scalar stop,
93  Scalar stride)
94 {
95  start_ = start;
96  stop_ = stop;
97  if (stop_ < start_) {
98  Scalar tmp = start_;
99  start_ = stop_;
100  stop_ = tmp;
101  }
102  setTimeScale();
103  setTimeStride(stride);
104 }
105 
106 template <class Scalar>
107 void TimeEventRange<Scalar>::setTimeRange(Scalar start, Scalar stop,
108  int numEvents)
109 {
110  start_ = start;
111  stop_ = stop;
112  if (stop_ < start_) {
113  Scalar tmp = start_;
114  start_ = stop_;
115  stop_ = tmp;
116  }
117  setTimeScale();
118  setNumEvents(numEvents);
119 }
120 
121 template <class Scalar>
123 {
124  start_ = start;
125  if (stop_ < start_) stop_ = start_;
126  setTimeScale();
127  setTimeStride(stride_); // Reset numEvents with the current stride.
128 }
129 
130 template <class Scalar>
132 {
133  stop_ = stop;
134  if (start_ > stop_) start_ = stop_;
135  setTimeScale();
136  setTimeStride(stride_); // Reset numEvents with the current stride.
137 }
138 
139 template <class Scalar>
141 {
142  timeScale_ = std::max(std::abs(start_), std::abs(stop_));
143  absTol_ = relTol_ * timeScale_;
144 
145  // Check if timeScale is near zero.
146  if (approxZero(timeScale_, absTol_)) {
147  timeScale_ = 1.0;
148  absTol_ = relTol_ * timeScale_;
149  }
150 }
151 
152 template <class Scalar>
154 {
156  if (approxEqualAbsTol(start_, stop_, absTol_)) {
157  stride_ = 0.0;
158  numEvents_ = 1;
159  return;
160  }
161 
162  if ((stride_ > stop_ - start_) || (stride_ < 2 * absTol_)) {
163  stride_ = stop_ - start_;
164  }
165 
166  numEvents_ = int((stop_ + absTol_ - start_) / stride_) + 1;
167 }
168 
169 template <class Scalar>
171 {
172  numEvents_ = numEvents;
173  if (numEvents_ < 0) { // Do not use numEvents_ to set stride! Reset
174  // numEvents_ from stride_.
175  if (stride_ < 2 * absTol_) stride_ = 2 * absTol_;
176  numEvents_ = int((stop_ + absTol_ - start_) / stride_) + 1;
177  return;
178  }
179  else if (approxEqualAbsTol(start_, stop_, absTol_)) {
180  numEvents_ = 1;
181  stride_ = 0.0;
182  stride_ = stop_ - start_;
183  }
184  else {
185  if (numEvents_ < 2) numEvents_ = 2;
186  stride_ = (stop_ - start_) / Scalar(numEvents_ - 1);
187  }
188 
189  // If stride_ is smaller than twice the absolute tolerance,
190  // the time steps cannot be differentiated!
191  if (stride_ <= 2 * absTol_) setTimeStride(2 * absTol_);
192 }
193 
194 template <class Scalar>
196 {
197  relTol_ = std::abs(relTol);
198  setTimeScale();
199 }
200 
201 template <class Scalar>
202 bool TimeEventRange<Scalar>::isTime(Scalar time) const
203 {
204  // Check if before first event.
205  if (time < start_ - absTol_) return false;
206 
207  // Check if after last event.
208  const Scalar timeOfLast = start_ + (numEvents_ - 1) * stride_;
209  if (time > timeOfLast + absTol_) return false;
210 
211  int numStrides = 0;
212  if (!approxZero(stride_, 2 * absTol_)) numStrides = (time - start_) / stride_;
213 
214  numStrides = std::min(std::max(0, numStrides), int(numEvents_ - 1));
215  const Scalar leftBracket = start_ + numStrides * stride_;
216 
217  // Check if close to left bracket.
218  if (approxEqualAbsTol(time, leftBracket, absTol_)) return true;
219 
220  // Check if close to right bracket.
221  const Scalar rightBracket = leftBracket + stride_;
222  if (approxEqualAbsTol(time, rightBracket, absTol_)) return true;
223 
224  return false;
225 }
226 
227 template <class Scalar>
229 {
230  return timeOfNextEvent(time) - time; // Neg. time indicates in the past.
231 }
232 
233 template <class Scalar>
235 {
236  // Check if before first event.
237  if (time < start_ - absTol_) return start_;
238 
239  const Scalar timeOfLast = start_ + (numEvents_ - 1) * stride_;
240  // Check if after or close to last event.
241  if (time > timeOfLast - absTol_) return std::numeric_limits<Scalar>::max();
242 
243  int numStrides = 0;
244  if (!approxZero(stride_, 2 * absTol_))
245  numStrides = int((time - start_) / stride_) + 1;
246  const Scalar timeEvent = start_ + numStrides * stride_;
247 
248  // Check timeEvent is near time. If so, return the next event.
249  if (approxEqualAbsTol(time, timeEvent, absTol_)) return timeEvent + stride_;
250 
251  return timeEvent;
252 }
253 
254 template <class Scalar>
255 bool TimeEventRange<Scalar>::eventInRange(Scalar time1, Scalar time2) const
256 {
257  if (time1 > time2) {
258  Scalar tmp = time1;
259  time1 = time2;
260  time2 = tmp;
261  }
262 
263  // Check if range is completely outside time events.
264  const Scalar timeOfLast = start_ + (numEvents_ - 1) * stride_;
265  if (time2 < start_ - absTol_ || timeOfLast + absTol_ < time1) return false;
266 
267  if (approxZero(stride_))
268  return (time1 < start_ - absTol_ && start_ - absTol_ <= time2);
269 
270  const int strideJustBeforeTime1 = std::min(
271  int(numEvents_ - 1),
272  std::max(int(0), int((time1 - start_ + absTol_) / stride_ - 0.5)));
273 
274  const int strideJustAfterTime2 = std::max(
275  int(0), std::min(int(numEvents_ - 1),
276  int((time2 - start_ + absTol_) / stride_ + 0.5)));
277 
278  for (int i = strideJustBeforeTime1; i <= strideJustAfterTime2; i++) {
279  const Scalar timeEvent = start_ + i * stride_;
280  if (time1 < timeEvent - absTol_ && timeEvent - absTol_ <= time2)
281  return true;
282  }
283 
284  return false;
285 }
286 
287 template <class Scalar>
289  Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
290 {
291  auto l_out = Teuchos::fancyOStream(out.getOStream());
292  Teuchos::OSTab ostab(*l_out, 2, "TimeEventRange");
293  l_out->setOutputToRootOnly(0);
294 
295  *l_out << "TimeEventRange:"
296  << "\n"
297  << " name = " << this->getName() << "\n"
298  << " Type = " << this->getType() << "\n"
299  << " start_ = " << start_ << "\n"
300  << " stop_ = " << stop_ << "\n"
301  << " stride_ = " << stride_ << "\n"
302  << " numEvents_ = " << numEvents_ << "\n"
303  << " timeScale_ = " << timeScale_ << "\n"
304  << " relTol_ = " << relTol_ << "\n"
305  << " absTol_ = " << absTol_ << "\n"
306  << " landOnExactly_ = " << landOnExactly_ << std::endl;
307 }
308 
309 template <class Scalar>
312 {
314  Teuchos::parameterList("Time Event Range");
315 
316  pl->setName(this->getName());
317  pl->set("Name", this->getName());
318  pl->set("Type", this->getType());
319 
320  pl->set("Start Time", getTimeStart(), "Start of time range");
321  pl->set("Stop Time", getTimeStop(), "Stop of time range");
322  pl->set("Stride Time", getTimeStride(), "Stride of time range");
323 
324  if (getTimeStride() * Scalar(getNumEvents() - 1) -
325  (getTimeStop() - getTimeStart()) <
326  getAbsTol())
327  pl->set("Number of Events", getNumEvents(),
328  "Number of events in time range. If specified, 'Stride Time' is "
329  "reset.");
330 
331  pl->set("Relative Tolerance", getRelTol(),
332  "Relative time tolerance for matching time events.");
333 
334  pl->set("Land On Exactly", getLandOnExactly(),
335  "Should these time events be landed on exactly, i.e, adjust the "
336  "timestep to hit time event, versus stepping over and keeping the "
337  "time step unchanged.");
338 
339  return pl;
340 }
341 
342 // Nonmember constructors.
343 // ------------------------------------------------------------------------
344 
345 template <class Scalar>
348 {
349  auto ter = Teuchos::rcp(new TimeEventRange<Scalar>());
350  if (pl == Teuchos::null) return ter; // Return default TimeEventRange.
351 
352  TEUCHOS_TEST_FOR_EXCEPTION(pl->get<std::string>("Type", "Range") != "Range",
353  std::logic_error,
354  "Error - Time Event Type != 'Range'. (='" +
355  pl->get<std::string>("Type") + "')\n");
356 
357  auto validPL = *ter->getValidParameters();
358  bool numEventsFound = pl->isParameter("Number of Events");
359  if (!numEventsFound) validPL.remove("Number of Events");
360 
362 
363  ter->setName(pl->get("Name", "From createTimeEventRange"));
364  ter->setTimeStart(pl->get("Start Time", ter->getTimeStart()));
365  ter->setTimeStop(pl->get("Stop Time", ter->getTimeStop()));
366  ter->setTimeStride(pl->get("Stride Time", ter->getTimeStride()));
367  if (numEventsFound)
368  ter->setNumEvents(pl->get("Number of Events", ter->getNumEvents()));
369  ter->setRelTol(pl->get("Relative Tolerance", ter->getRelTol()));
370  ter->setLandOnExactly(pl->get("Land On Exactly", ter->getLandOnExactly()));
371 
372  return ter;
373 }
374 
375 } // namespace Tempus
376 #endif // Tempus_TimeEventRange_impl_hpp
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a valid ParameterList with current settings.
virtual void setType(std::string s)
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Describe member data.
virtual void setRelTol(Scalar relTol)
Set the relative tolerance.
Scalar stride_
Stride of time range.
virtual void setNumEvents(int numEvents)
Set the number of time events.
virtual void setName(std::string name)
Set the name of the TimeEvent.
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void setLandOnExactly(bool LOE)
Set if the time event should be landed on exactly.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Scalar start_
Start of time range.
bool isParameter(const std::string &name) const
virtual bool eventInRange(Scalar time1, Scalar time2) const
Test if an event occurs within the time range.
virtual Scalar getDefaultTol() const
Return the default tolerance used by TimeEvents.
TimeEventRange specifies a start, stop and stride time.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual Scalar timeToNextEvent(Scalar time) const
How much time until the next event.
Teuchos::RCP< TimeEventRange< Scalar > > createTimeEventRange(Teuchos::RCP< Teuchos::ParameterList > pList)
Nonmember Constructor via ParameterList.
virtual void setTimeStop(Scalar stop)
Set the stop of the time range.
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
virtual void setTimeScale()
Set the time scale for the time events.
static magnitudeType magnitude(T a)
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
bool approxEqualAbsTol(Scalar a, Scalar b, Scalar absTol)
Test if values are approximately equal within the absolute tolerance.
bool approxZero(Scalar value, Scalar tol=Teuchos::ScalarTraits< Scalar >::sfmin())
Test if value is approximately zero within tolerance.
virtual void setTimeStart(Scalar start)
Set the start of the time range.
Scalar stop_
Stop of time range.
ParameterList & setName(const std::string &name)
virtual void setTimeStride(Scalar stride)
Set the stride of the time range.
virtual bool isTime(Scalar time) const
Test if time is near an event (within tolerance).
TimeEventRange()
Default constructor.
virtual Scalar timeOfNextEvent(Scalar time) const
Return the time of the next event following the input time.
virtual void setTimeRange(Scalar start, Scalar stop, Scalar stride)
Set the range of time events from start, stop and stride.