Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
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
15namespace Tempus {
16
17template <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());
28 setLandOnExactly(true);
29}
30
31template <class Scalar>
32TimeEventList<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);
44 setLandOnExactly(landOnExactly);
45 setTimeList(timeList);
46}
47
48template <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
68template <class Scalar>
69void 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
79template <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
113template <class Scalar>
115{
116 relTol_ = std::abs(relTol);
117 setTimeScale();
118}
119
120template <class Scalar>
121bool 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
129template <class Scalar>
131{
132 return timeOfNextEvent(time) - time; // Neg. indicating in the past.
133}
134
135template <class Scalar>
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
157template <class Scalar>
158bool 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
174template <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
201template <class Scalar>
202Teuchos::RCP<const Teuchos::ParameterList>
204{
205 Teuchos::RCP<Teuchos::ParameterList> pl =
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
235template <class Scalar>
236Teuchos::RCP<TimeEventList<Scalar> > createTimeEventList(
237 Teuchos::RCP<Teuchos::ParameterList> pl)
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 void setType(std::string s)
virtual void setName(std::string name)
Set the name of the TimeEvent.
virtual Scalar getDefaultTol() const
Return the default tolerance used by TimeEvents.
TimeEventList specifies a list of time events.
virtual Scalar timeToNextEvent(Scalar time) const
How much time until the next event.
virtual Scalar timeOfNextEvent(Scalar time) const
Return the time of the next event following the input time.
virtual bool isTime(Scalar time) const
Test if time is near an event (within tolerance).
TimeEventList()
Default constructor.
virtual void setTimeScale()
Set the time scale for the time events.
virtual void addTime(Scalar time)
Add the time to event vector.
virtual bool eventInRange(Scalar time1, Scalar time2) const
Test if an event occurs within the time range.
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a valid ParameterList with current settings.
virtual void setRelTol(Scalar relTol)
Set the relative tolerance.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Describe member data.
virtual void setLandOnExactly(bool LOE)
Set if the time event should be landed on exactly.
virtual void setTimeList(std::vector< Scalar > timeList, bool sort=true)
Set the list of time events.
bool approxZero(Scalar value, Scalar tol=Teuchos::ScalarTraits< Scalar >::sfmin())
Test if value is approximately zero within tolerance.
bool approxEqualAbsTol(Scalar a, Scalar b, Scalar absTol)
Test if values are approximately equal within the absolute tolerance.
Teuchos::RCP< TimeEventList< Scalar > > createTimeEventList(Teuchos::RCP< Teuchos::ParameterList > pList)
Nonmember Constructor via ParameterList.