Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_TimeEventList_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_TimeEventList_impl_hpp
11 #define Tempus_TimeEventList_impl_hpp
12 
14 
15 namespace Tempus {
16 
17 template <class Scalar>
19  : timeScale_(1.0),
20  relTol_(this->getDefaultTol()),
21  absTol_(this->getDefaultTol()),
22  landOnExactly_(true)
23 {
24  this->setType("List");
25  this->setName("TimeEventList");
26  setRelTol(this->getDefaultTol());
27  setTimeScale();
28  setLandOnExactly(true);
29 }
30 
31 template <class Scalar>
32 TimeEventList<Scalar>::TimeEventList(std::vector<Scalar> timeList,
33  std::string name, bool landOnExactly,
34  Scalar relTol)
35  : timeScale_(1.0),
36  relTol_(this->getDefaultTol()),
37  absTol_(this->getDefaultTol()),
38  landOnExactly_(true)
39 {
40  this->setType("List");
41  this->setName(name);
42  setRelTol(relTol);
43  setTimeScale();
44  setLandOnExactly(landOnExactly);
45  setTimeList(timeList);
46 }
47 
48 template <class Scalar>
50 {
51  if (timeList_.size() == 0) {
52  timeScale_ = 1.0;
53  absTol_ = relTol_ * timeScale_;
54  return;
55  }
56 
57  timeScale_ =
58  std::max(std::abs(timeList_.front()), std::abs(timeList_.back()));
59  absTol_ = relTol_ * timeScale_;
60 
61  // Check if timeScale is near zero.
62  if (approxZero(timeScale_, absTol_)) {
63  timeScale_ = 1.0;
64  absTol_ = relTol_ * timeScale_;
65  }
66 }
67 
68 template <class Scalar>
69 void TimeEventList<Scalar>::setTimeList(std::vector<Scalar> timeList, bool sort)
70 {
71  timeList_ = timeList;
72  if (sort) {
73  std::sort(timeList_.begin(), timeList_.end());
74  timeList_.erase(std::unique(timeList_.begin(), timeList_.end()),
75  timeList_.end());
76  }
77 }
78 
79 template <class Scalar>
81 {
82  if (timeList_.size() == 0) {
83  timeList_.push_back(time);
84  setTimeScale();
85  return;
86  }
87 
88  auto it = std::upper_bound(timeList_.begin(), timeList_.end(), time);
89  if (timeList_.size() == 1) {
90  // Only add if a "different" time.
91  if (std::abs(timeList_.front() - time) >= absTol_)
92  timeList_.insert(it, time);
93  setTimeScale();
94  return;
95  }
96 
97  // Don't add if already in list. Check both ends.
98  if (it == timeList_.begin()) {
99  if (std::abs(timeList_.front() - time) >= absTol_)
100  timeList_.insert(it, time);
101  }
102  else if (it == timeList_.end()) {
103  if (std::abs(timeList_.back() - time) >= absTol_)
104  timeList_.insert(it, time);
105  }
106  else if (std::abs(*(it - 1) - time) >= absTol_ &&
107  std::abs(*(it)-time) >= absTol_) {
108  timeList_.insert(it, time);
109  }
110  setTimeScale();
111 }
112 
113 template <class Scalar>
115 {
116  relTol_ = std::abs(relTol);
117  setTimeScale();
118 }
119 
120 template <class Scalar>
121 bool TimeEventList<Scalar>::isTime(Scalar time) const
122 {
123  for (auto it = timeList_.begin(); it != timeList_.end(); ++it)
124  if (approxEqualAbsTol(time, *it, absTol_)) return true;
125 
126  return false;
127 }
128 
129 template <class Scalar>
130 Scalar TimeEventList<Scalar>::timeToNextEvent(Scalar time) const
131 {
132  return timeOfNextEvent(time) - time; // Neg. indicating in the past.
133 }
134 
135 template <class Scalar>
136 Scalar TimeEventList<Scalar>::timeOfNextEvent(Scalar time) const
137 {
138  if (timeList_.size() == 0) return this->getDefaultTime();
139 
140  // Check if before first event.
141  if (time < timeList_.front() - absTol_) return timeList_.front();
142 
143  // Check if after or close to last event.
144  if (time > timeList_.back() - absTol_)
145  return std::numeric_limits<Scalar>::max();
146 
147  typename std::vector<Scalar>::const_iterator it =
148  std::upper_bound(timeList_.begin(), timeList_.end(), time);
149  const Scalar timeEvent = *it;
150 
151  // Check timeEvent is near time. If so, return the next event.
152  if (approxEqualAbsTol(time, timeEvent, absTol_)) return *(it + 1);
153 
154  return timeEvent;
155 }
156 
157 template <class Scalar>
158 bool TimeEventList<Scalar>::eventInRange(Scalar time1, Scalar time2) const
159 {
160  if (time1 > time2) {
161  Scalar tmp = time1;
162  time1 = time2;
163  time2 = tmp;
164  }
165 
166  if (timeList_.size() == 0) return false;
167 
168  for (auto it = timeList_.begin(); it != timeList_.end(); ++it)
169  if (time1 + absTol_ < *it && *it < time2 + absTol_) return true;
170 
171  return false;
172 }
173 
174 template <class Scalar>
176  Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
177 {
178  auto l_out = Teuchos::fancyOStream(out.getOStream());
179  Teuchos::OSTab ostab(*l_out, 2, "TimeEventList");
180  l_out->setOutputToRootOnly(0);
181 
182  *l_out << "TimeEventList:"
183  << "\n"
184  << " name = " << this->getName() << "\n"
185  << " Type = " << this->getType() << "\n"
186  << " timeScale_ = " << timeScale_ << "\n"
187  << " relTol_ = " << relTol_ << "\n"
188  << " absTol_ = " << absTol_ << "\n"
189  << " landOnExactly_ = " << landOnExactly_ << "\n"
190  << " timeList_ = ";
191  if (!timeList_.empty()) {
192  for (auto it = timeList_.begin(); it != timeList_.end() - 1; ++it)
193  *l_out << *it << ", ";
194  *l_out << *(timeList_.end() - 1) << std::endl;
195  }
196  else {
197  *l_out << "<empty>" << std::endl;
198  }
199 }
200 
201 template <class Scalar>
204 {
206  Teuchos::parameterList("Time Event List");
207 
208  pl->setName(this->getName());
209  pl->set("Name", this->getName());
210  pl->set("Type", this->getType());
211 
212  pl->set("Relative Tolerance", this->getRelTol(),
213  "Relative time tolerance for matching time events.");
214 
215  pl->set("Land On Exactly", this->getLandOnExactly(),
216  "Should these time events be landed on exactly, i.e, adjust the "
217  "timestep to hit time event, versus stepping over and keeping the "
218  "time step unchanged.");
219 
220  std::vector<Scalar> times = this->getTimeList();
221  std::ostringstream list;
222  if (!times.empty()) {
223  for (std::size_t i = 0; i < times.size() - 1; ++i) list << times[i] << ", ";
224  list << times[times.size() - 1];
225  }
226  pl->set<std::string>("Time List", list.str(),
227  "Comma deliminated list of times");
228 
229  return pl;
230 }
231 
232 // Nonmember constructors.
233 // ------------------------------------------------------------------------
234 
235 template <class Scalar>
238 {
239  auto tel = Teuchos::rcp(new TimeEventList<Scalar>());
240  if (pl == Teuchos::null) return tel; // Return default TimeEventList.
241 
242  TEUCHOS_TEST_FOR_EXCEPTION(pl->get<std::string>("Type", "List") != "List",
243  std::logic_error,
244  "Error - Time Event Type != 'List'. (='" +
245  pl->get<std::string>("Type") + "')\n");
246 
247  pl->validateParametersAndSetDefaults(*tel->getValidParameters());
248 
249  tel->setName(pl->get("Name", "From createTimeEventList"));
250  tel->setRelTol(pl->get("Relative Tolerance", tel->getRelTol()));
251  tel->setLandOnExactly(pl->get("Land On Exactly", tel->getLandOnExactly()));
252 
253  std::vector<Scalar> timeList;
254  std::string str = pl->get<std::string>("Time List");
255  std::string delimiters(",");
256  // Skip delimiters at the beginning
257  std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
258  // Find the first delimiter
259  std::string::size_type pos = str.find_first_of(delimiters, lastPos);
260  while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
261  // Found a token, add it to the vector
262  std::string token = str.substr(lastPos, pos - lastPos);
263  timeList.push_back(Scalar(std::stod(token)));
264  if (pos == std::string::npos) break;
265 
266  lastPos = str.find_first_not_of(delimiters, pos); // Skip delimiters
267  pos = str.find_first_of(delimiters, lastPos); // Find next delimiter
268  }
269  tel->setTimeList(timeList);
270 
271  return tel;
272 }
273 
274 } // namespace Tempus
275 #endif // Tempus_TimeEventList_impl_hpp
virtual bool isTime(Scalar time) const
Test if time is near an event (within tolerance).
virtual void setType(std::string s)
virtual void setName(std::string name)
Set the name of the TimeEvent.
T & get(const std::string &name, T def_value)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a valid ParameterList with current settings.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
virtual void addTime(Scalar time)
Add the time to event vector.
virtual Scalar timeOfNextEvent(Scalar time) const
Return the time of the next event following the input time.
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.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void setTimeScale()
Set the time scale for the time events.
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
virtual void setRelTol(Scalar relTol)
Set the relative tolerance.
virtual void setTimeList(std::vector< Scalar > timeList, bool sort=true)
Set the list of time events.
TimeEventList()
Default constructor.
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Describe member data.
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 Scalar timeToNextEvent(Scalar time) const
How much time until the next event.
ParameterList & setName(const std::string &name)
virtual void setLandOnExactly(bool LOE)
Set if the time event should be landed on exactly.
TimeEventList specifies a list of time events.
Teuchos::RCP< TimeEventList< Scalar > > createTimeEventList(Teuchos::RCP< Teuchos::ParameterList > pList)
Nonmember Constructor via ParameterList.