SyDEVS  v0.6.7
Multiscale Simulation and Systems Modeling Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
simulation.h
Go to the documentation of this file.
1 #pragma once
2 #ifndef SYDEVS_SYSTEMS_SIMULATION_H_
3 #define SYDEVS_SYSTEMS_SIMULATION_H_
4 
8 
9 namespace sydevs {
10 namespace systems {
11 
12 
72 template<typename Node>
74 {
75 public:
91  simulation(const time_point& start_t, const time_point& end_t, bool can_end_early, int64 seed, std::ostream& stream);
92 
105  simulation(duration total_dt, int64 seed, std::ostream& stream);
106 
107  simulation(const simulation&) = delete;
108  simulation& operator=(const simulation&) = delete;
109  simulation(simulation&&) = delete;
110  simulation& operator=(simulation&&) = delete;
111  virtual ~simulation() = default;
112 
113  const time_point& start_time() const;
114  const time_point& end_time() const;
115  bool can_end_early() const;
116 
117  bool started() const;
118  bool finishing() const;
119  bool finished() const;
120 
121  const discrete_event_time& time() const;
122  duration imminent_duration() const;
123 
124  void process_next_event();
128 
129  const timer& event_timer() const;
130 
131 private:
132  node_interface& top_IO();
133  discrete_event_time& event_time();
134  void validate();
135 
136  void process_initialization_event();
137  void process_planned_event();
138  void process_finalization_event();
139  void advance_time();
140 
141  const time_point start_t_; // (must be declared before member variable external_context_)
142  const time_point end_t_;
143  bool can_end_early_;
144  node_context external_context_; // (must be declared before member variable top)
145  bool started_;
146  bool finishing_;
147  bool finished_;
148  time_queue t_queue_;
149  time_cache t_cache_;
150  timer event_timer_;
151 
152 public:
153  Node top;
154 };
155 
156 
157 template<typename Node>
158 inline simulation<Node>::simulation(const time_point& start_t, const time_point& end_t, bool can_end_early, int64 seed, std::ostream& stream)
159  : start_t_(start_t)
160  , end_t_(end_t)
161  , can_end_early_(can_end_early)
162  , external_context_(start_t, seed, stream)
163  , started_(false)
164  , finishing_(false)
165  , finished_(false)
166  , t_queue_(start_t)
167  , t_cache_(start_t)
168  , event_timer_()
169  , top("top", external_context_)
170 {
171  validate();
172 }
173 
174 
175 template<typename Node>
176 inline simulation<Node>::simulation(duration total_dt, int64 seed, std::ostream& stream)
177  : start_t_()
178  , end_t_(total_dt.finite() ? time_point() + total_dt :
179  time_point() + duration(1, scale(std::numeric_limits<scale::level_type>::max() - 6)))
180  , can_end_early_(!total_dt.finite())
181  , external_context_(start_t_, seed, stream)
182  , started_(false)
183  , finishing_(false)
184  , finished_(false)
185  , t_queue_()
186  , t_cache_()
187  , event_timer_()
188  , top("top", external_context_)
189 {
190  validate();
191 }
192 
193 
194 template<typename Node>
196 {
197  return start_t_;
198 }
199 
200 
201 template<typename Node>
203 {
204  return end_t_;
205 }
206 
207 
208 template<typename Node>
210 {
211  return can_end_early_;
212 }
213 
214 
215 template<typename Node>
216 inline bool simulation<Node>::started() const
217 {
218  return started_;
219 }
220 
221 
222 template<typename Node>
223 inline bool simulation<Node>::finishing() const
224 {
225  return finishing_;
226 }
227 
228 
229 template<typename Node>
230 inline bool simulation<Node>::finished() const
231 {
232  return finished_;
233 }
234 
235 
236 template<typename Node>
238 {
239  return const_cast<node_context&>(external_context_).event_time();
240 }
241 
242 
243 template<typename Node>
245 {
246  return t_queue_.imminent_duration();
247 }
248 
249 
250 template<typename Node>
252 {
253  if (!finished_) {
254  if (!finishing_) {
255  if (!started_) {
256  process_initialization_event();
257  }
258  else {
259  process_planned_event();
260  }
261  advance_time();
262  }
263  else {
264  process_finalization_event();
265  }
266  }
267 }
268 
269 
270 template<typename Node>
272 {
273  int64 event_count = 0;
274  auto t = event_time().t();
275  while (!finished_ && event_time().t() == t) {
276  process_next_event();
277  ++event_count;
278  }
279  return event_count;
280 }
281 
282 
283 template<typename Node>
285 {
286  int64 event_count = 0;
287  while (!finished_ && event_time().t() < t) {
288  process_next_event();
289  ++event_count;
290  }
291  return event_count;
292 }
293 
294 
295 template<typename Node>
297 {
298  int64 event_count = 0;
299  while (!finished_) {
300  process_next_event();
301  ++event_count;
302  }
303  return event_count;
304 }
305 
306 
307 template<typename Node>
309 {
310  return event_timer_;
311 }
312 
313 
314 template<typename Node>
316 {
317  return const_cast<node_interface&>(top.external_interface());
318 }
319 
320 
321 template<typename Node>
322 inline discrete_event_time& simulation<Node>::event_time()
323 {
324  return external_context_.event_time();
325 }
326 
327 
328 template<typename Node>
329 inline void simulation<Node>::validate()
330 {
331  static_assert(std::is_base_of<system_node, Node>::value, "Node must inherit from system_node");
332 
333  if (top_IO().flow_input_port_count() != 0 ||
334  top_IO().message_input_port_count() != 0 ||
335  top_IO().message_output_port_count() != 0 ||
336  top_IO().flow_output_port_count() != 0) {
337  throw std::invalid_argument("Node to be simulated must have no ports");
338  }
339 }
340 
341 
342 template<typename Node>
343 inline void simulation<Node>::process_initialization_event()
344 {
345  started_ = true;
346  top_IO().print_event("initialization");
347  top_IO().activate(flow, input);
348  event_timer_.start();
349  auto planned_dt = top.process_initialization_event();
350  event_timer_.stop();
351  top_IO().deactivate();
352  if (planned_dt.finite()) {
353  t_queue_.plan_event(0, planned_dt);
354  }
355  if (top.time_precision() != no_scale) {
356  t_cache_.retain_event(0, top.time_precision());
357  }
358 }
359 
360 
361 template<typename Node>
362 inline void simulation<Node>::process_planned_event()
363 {
364  top_IO().print_event("planned");
365  auto elapsed_dt = duration();
366  if (top.time_precision() != no_scale) {
367  elapsed_dt = t_cache_.duration_since(0).fixed_at(top.time_precision());
368  }
369  top_IO().activate(message, output);
370  event_timer_.start();
371  auto planned_dt = top.process_planned_event(elapsed_dt);
372  event_timer_.stop();
373  top_IO().deactivate();
374  if (planned_dt.finite()) {
375  t_queue_.plan_event(0, planned_dt);
376  }
377  else {
378  t_queue_.pop_imminent_event(0);
379  }
380  if (top.time_precision() != no_scale) {
381  t_cache_.retain_event(0, top.time_precision());
382  }
383 }
384 
385 
386 template<typename Node>
387 inline void simulation<Node>::process_finalization_event()
388 {
389  top_IO().print_event("finalization");
390  auto elapsed_dt = duration();
391  if (top.time_precision() != no_scale) {
392  elapsed_dt = t_cache_.duration_since(0).fixed_at(top.time_precision());
393  }
394  top_IO().activate(flow, output);
395  event_timer_.start();
396  top.process_finalization_event(elapsed_dt);
397  event_timer_.stop();
398  top_IO().deactivate();
399  finished_ = true;
400 }
401 
402 
403 template<typename Node>
404 inline void simulation<Node>::advance_time()
405 {
406  if (!finishing_) {
407  auto planned_dt = t_queue_.imminent_duration();
408  if (planned_dt.finite() || !can_end_early_) {
409  // The event time must advance.
410  event_time().advance(planned_dt, end_t_);
411  if (planned_dt > 0_s) {
412  // The simulated time just advanced.
413  external_context_.time_printed() = false;
414  t_queue_.advance_time(event_time().t());
415  t_cache_.advance_time(event_time().t());
416  }
417  if (event_time().t() >= end_t_) {
418  // The end time has been reached.
419  finishing_ = true;
420  }
421  }
422  else {
423  // The simulation must finish at the current event time.
424  finishing_ = true;
425  }
426  }
427 }
428 
429 
430 } // namespace
431 } // namespace
432 
433 #endif
const auto output
Equivalent to data_goal::output.
Definition: data_goal.h:22
const auto input
Equivalent to data_goal::input.
Definition: data_goal.h:21
bool can_end_early() const
Returns true if the simulation can end before the specified end time.
Definition: simulation.h:209
A data structure which represents progress through a simulation, encapsulating both simulated time an...
Definition: discrete_event_time.h:36
virtual ~simulation()=default
Destructor.
Node top
The topmost system node.
Definition: simulation.h:153
const time_point & end_time() const
Returns the end time of the simulation.
Definition: simulation.h:202
constexpr scale no_scale
Definition: scale.h:153
bool finishing() const
Returns true if all events are finished except finalization.
Definition: simulation.h:223
A class for measuring and accumulating intervals of wallclock time.
Definition: timer.h:24
constexpr auto _s
Definition: units.h:128
int64 process_next_events()
Runs all events until simulated time advances; returns the number of processed events.
Definition: simulation.h:271
A data structure which provides durations elapsed since past events.
Definition: time_cache.h:27
int64 process_remaining_events()
Runs simulation until completion; returns the number of processed events.
Definition: simulation.h:296
int64 process_events_until(const time_point &t)
Runs all events until simulated time advances at least to t; returns the number of processed events...
Definition: simulation.h:284
A data type which represents the general concept of scale as a dimensionless power of 1000...
Definition: scale.h:70
const time_point & start_time() const
Returns the start time of the simulation.
Definition: simulation.h:195
bool finished() const
Returns true if the simulation has finished.
Definition: simulation.h:230
const discrete_event_time & time() const
Returns the current point in discrete event time.
Definition: simulation.h:237
A data structure which represents a point in time as an arbitrary-precision multiple of its shortest ...
Definition: time_point.h:84
const timer & event_timer() const
Returns the object that accumulated wallclock event durations.
Definition: simulation.h:308
duration imminent_duration() const
Returns the duration until the imminent event.
Definition: simulation.h:244
A data structure which supports the scheduling of future events.
Definition: time_queue.h:34
A class template for running simulations.
Definition: simulation.h:73
Definition: node_context.h:16
Definition: node_interface.h:16
bool started() const
Returns true if the simulation has started.
Definition: simulation.h:216
const auto flow
Equivalent to data_mode::flow.
Definition: data_mode.h:22
quantity< seconds > duration
Definition: quantity.h:1006
const auto message
Equivalent to data_mode::message.
Definition: data_mode.h:23
void process_next_event()
Runs the next event of the topmost system node.
Definition: simulation.h:251
simulation & operator=(const simulation &)=delete
No copy assignment.
simulation(const time_point &start_t, const time_point &end_t, bool can_end_early, int64 seed, std::ostream &stream)
Constructs a simulation with the full set of configuration options.
Definition: simulation.h:158