adevs
adevs_simulator.h
1 
31 #ifndef __adevs_simulator_h_
32 #define __adevs_simulator_h_
33 #include "adevs_abstract_simulator.h"
34 #include "adevs_models.h"
35 #include "adevs_event_listener.h"
36 #include "adevs_sched.h"
37 #include "adevs_bag.h"
38 #include "adevs_set.h"
39 #include "object_pool.h"
40 #include "adevs_lp.h"
41 #include <cassert>
42 #include <cstdlib>
43 #include <iostream>
44 #include <vector>
45 
46 namespace adevs
47 {
48 
55 template <class X, class T = double> class Simulator:
56  public AbstractSimulator<X,T>,
57  private Schedule<X,T>::ImminentVisitor
58 {
59  public:
67  AbstractSimulator<X,T>(),
68  Schedule<X,T>::ImminentVisitor(),
69  lps(NULL)
70  {
71  schedule(model,adevs_zero<T>());
72  }
78  {
79  return sched.minPriority();
80  }
83  {
85  computeNextState(bogus_input,sched.minPriority());
86  }
88  void execUntil(T tend)
89  {
90  while (nextEventTime() <= tend
91  && nextEventTime() < adevs_inf<T>()) {
92  execNextEvent();
93  }
94  }
100  void computeNextOutput();
109  void computeNextState(Bag<Event<X,T> >& input, T t);
115  ~Simulator();
120  void addModel(Atomic<X,T>* model)
121  {
122  schedule(model,adevs_zero<T>());
123  }
128  Simulator(LogicalProcess<X,T>* lp);
140  void beginLookahead();
145  void endLookahead();
152  void lookNextEvent();
153  private:
154  typedef enum { OUTPUT_OK, OUTPUT_NOT_OK, RESTORING_OUTPUT } OutputStatus;
155  // Structure to support parallel computing by a logical process
156  struct lp_support
157  {
158  // The processor that this simulator works for
159  LogicalProcess<X,T>* lp;
160  bool look_ahead, stop_forced;
161  OutputStatus out_flag;
162  Bag<Atomic<X,T>*> to_restore;
163  };
164  // This is NULL if the simulator is not supporting a logical process
165  lp_support* lps;
166  // Bogus input bag for execNextEvent() method
167  Bag<Event<X,T> > bogus_input;
168  // The event schedule
169  Schedule<X,T> sched;
170  // List of models that are imminent or activated by input
171  Bag<Atomic<X,T>*> activated;
172  // Pools of preallocated, commonly used objects
173  object_pool<Bag<X> > io_pool;
174  object_pool<Bag<Event<X,T> > > recv_pool;
175  // Sets for computing structure changes.
176  Bag<Devs<X,T>*> added;
177  Bag<Devs<X,T>*> removed;
178  Set<Devs<X,T>*> next;
179  Set<Devs<X,T>*> prev;
180  // Model transition functions are evaluated from the bottom up!
181  struct bottom_to_top_depth_compare
182  {
183  bool operator()(const Network<X,T>* m1, const Network<X,T>* m2) const
184  {
185  unsigned long int d1 = 0, d2 = 0;
186  // Compute depth of m1
187  const Network<X,T>* m = m1->getParent();
188  while (m != NULL)
189  {
190  d1++;
191  m = m->getParent();
192  }
193  // Compute depth of m2
194  m = m2->getParent();
195  while (m != NULL)
196  {
197  d2++;
198  m = m->getParent();
199  }
200  // Models at the same depth are sorted by name
201  if (d1 == d2) return m1 < m2;
202  // Otherwise, sort by depth
203  return d1 > d2;
204  }
205  };
206  struct top_to_bottom_depth_compare
207  {
208  bool operator()(const Devs<X,T>* m1, const Devs<X,T>* m2) const
209  {
210  unsigned long int d1 = 0, d2 = 0;
211  // Compute depth of m1
212  const Network<X,T>* m = m1->getParent();
213  while (m != NULL)
214  {
215  d1++;
216  m = m->getParent();
217  }
218  // Compute depth of m2
219  m = m2->getParent();
220  while (m != NULL)
221  {
222  d2++;
223  m = m->getParent();
224  }
225  // Models at the same depth are sorted by name
226  if (d1 == d2) return m1 < m2;
227  // Otherwise, sort by depth
228  return d1 < d2;
229  }
230  };
231  std::set<Network<X,T>*,bottom_to_top_depth_compare> model_func_eval_set;
232  std::set<Devs<X,T>*,top_to_bottom_depth_compare> sorted_removed;
237  void schedule(Devs<X,T>* model, T t);
239  void route(Network<X,T>* parent, Devs<X,T>* src, X& x);
245  void inject_event(Atomic<X,T>* model, X& value);
250  void unschedule_model(Devs<X,T>* model);
256  void clean_up(Devs<X,T>* model);
263  void exec_event(Atomic<X,T>* model, T t);
267  void getAllChildren(Network<X,T>* model, Set<Devs<X,T>*>& s);
273  bool manage_lookahead_data(Atomic<X,T>* model);
277  void visit(Atomic<X,T>* model);
278 };
279 
280 template <class X, class T>
281 void Simulator<X,T>::visit(Atomic<X,T>* model)
282 {
283  assert(model->y == NULL);
284  model->y = io_pool.make_obj();
285  // Put it in the active list if it is not already there
286  if (model->x == NULL)
287  activated.insert(model);
288  // Compute output functions and route the events. The bags of output
289  // are held for garbage collection at a later time.
290  model->output_func(*(model->y));
291  // Route each event in y
292  for (typename Bag<X>::iterator y_iter = model->y->begin();
293  y_iter != model->y->end(); y_iter++)
294  {
295  route(model->getParent(),model,*y_iter);
296  }
297 }
298 
299 template <class X, class T>
301 {
302  // If the imminent set is up to date, then just return
303  if (activated.empty() == false) return;
304  // Get the imminent models from the schedule.
305  sched.visitImminent(this);
306 }
307 
308 template <class X, class T>
310 {
311  // Clean up if there was a previous IO calculation
312  if (t < sched.minPriority())
313  {
314  typename Bag<Atomic<X,T>*>::iterator iter;
315  for (iter = activated.begin(); iter != activated.end(); iter++)
316  {
317  clean_up(*iter);
318  }
319  activated.clear();
320  }
321  // Otherwise, if the internal IO needs to be computed, do it
322  else if (t == sched.minPriority())
323  {
324  computeNextOutput();
325  }
326  // Apply the injected inputs
327  for (typename Bag<Event<X,T> >::iterator iter = input.begin();
328  iter != input.end(); iter++)
329  {
330  Atomic<X,T>* amodel = (*iter).model->typeIsAtomic();
331  if (amodel != NULL)
332  {
333  inject_event(amodel,(*iter).value);
334  }
335  else
336  {
337  route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value);
338  }
339  }
340  /*
341  * Compute the states of atomic models. Store Network models that
342  * need to have their model transition function evaluated in a
343  * special container that will be used when the structure changes are
344  * computed (see exec_event(.)).
345  */
346  for (typename Bag<Atomic<X,T>*>::iterator iter = activated.begin();
347  iter != activated.end(); iter++)
348  {
349  exec_event(*iter,t);
350  }
357  if (model_func_eval_set.empty() == false)
358  {
359  while (!model_func_eval_set.empty())
360  {
361  Network<X,T>* network_model = *(model_func_eval_set.begin());
362  model_func_eval_set.erase(model_func_eval_set.begin());
363  getAllChildren(network_model,prev);
364  if (network_model->model_transition() &&
365  network_model->getParent() != NULL)
366  {
367  model_func_eval_set.insert(network_model->getParent());
368  }
369  getAllChildren(network_model,next);
370  }
371  // Find the set of models that were added.
372  set_assign_diff(added,next,prev);
373  // Find the set of models that were removed
374  set_assign_diff(removed,prev,next);
375  // Intersection of added and removed is always empty, so no need to look
376  // for models in both (an earlier version of the code did this).
377  next.clear();
378  prev.clear();
385  for (typename Bag<Devs<X,T>*>::iterator iter = added.begin();
386  iter != added.end(); iter++)
387  {
388  schedule(*iter,t);
389  }
390  // Done with the additions
391  added.clear();
392  // Remove the models that are in the removed set.
393  for (typename Bag<Devs<X,T>*>::iterator iter = removed.begin();
394  iter != removed.end(); iter++)
395  {
396  clean_up(*iter);
397  unschedule_model(*iter);
398  // Add to a sorted remove set for deletion
399  sorted_removed.insert(*iter);
400  }
401  // Done with the unsorted remove set
402  removed.clear();
403  // Delete the sorted removed models
404  while (!sorted_removed.empty())
405  {
406  // Get the model to erase
407  Devs<X,T>* model_to_remove = *(sorted_removed.begin());
408  // Remove the model
409  sorted_removed.erase(sorted_removed.begin());
414  if (model_to_remove->typeIsNetwork() != NULL)
415  {
416  getAllChildren(model_to_remove->typeIsNetwork(),prev);
417  typename Set<Devs<X,T>*>::iterator iter = prev.begin();
418  for (; iter != prev.end(); iter++)
419  sorted_removed.erase(*iter);
420  prev.clear();
421  }
422  // Delete the model and its children
423  delete model_to_remove;
424  }
425  // Removed sets should be empty now
426  assert(prev.empty());
427  assert(sorted_removed.empty());
428  } // End of the structure change
429  // Cleanup and reschedule models that changed state in this iteration
430  // and survived the structure change phase.
431  for (typename Bag<Atomic<X,T>*>::iterator iter = activated.begin();
432  iter != activated.end(); iter++)
433  {
434  clean_up(*iter);
435  schedule(*iter,t);
436  }
437  // Empty the bags
438  activated.clear();
439  // If we are looking ahead, throw an exception if a stop was forced
440  if (lps != NULL && lps->stop_forced)
441  {
443  throw err;
444  }
445 }
446 
447 template <class X, class T>
449 {
450  Atomic<X,T>* amodel = model->typeIsAtomic();
451  if (amodel != NULL)
452  {
453  if (amodel->x != NULL)
454  {
455  amodel->x->clear();
456  io_pool.destroy_obj(amodel->x);
457  amodel->x = NULL;
458  }
459  if (amodel->y != NULL)
460  {
461  amodel->gc_output(*(amodel->y));
462  amodel->y->clear();
463  io_pool.destroy_obj(amodel->y);
464  amodel->y = NULL;
465  }
466  }
467  else
468  {
469  Set<Devs<X,T>*> components;
470  model->typeIsNetwork()->getComponents(components);
471  for (typename Set<Devs<X,T>*>::iterator iter = components.begin();
472  iter != components.end(); iter++)
473  {
474  clean_up(*iter);
475  }
476  }
477 }
478 
479 template <class X, class T>
480 void Simulator<X,T>::unschedule_model(Devs<X,T>* model)
481 {
482  if (model->typeIsAtomic() != NULL)
483  {
484  sched.schedule(model->typeIsAtomic(),adevs_inf<T>());
485  activated.erase(model->typeIsAtomic());
486  }
487  else
488  {
489  Set<Devs<X,T>*> components;
490  model->typeIsNetwork()->getComponents(components);
491  for (typename Set<Devs<X,T>*>::iterator iter = components.begin();
492  iter != components.end(); iter++)
493  {
494  unschedule_model(*iter);
495  }
496  }
497 }
498 
499 template <class X, class T>
500 void Simulator<X,T>::schedule(Devs<X,T>* model, T t)
501 {
502  Atomic<X,T>* a = model->typeIsAtomic();
503  if (a != NULL)
504  {
505  a->tL = t;
506  T dt = a->ta();
507  if (dt < adevs_zero<T>())
508  {
509  exception err("Negative time advance",a);
510  throw err;
511  }
512  if (dt == adevs_inf<T>())
513  sched.schedule(a,adevs_inf<T>());
514  else
515  sched.schedule(a,t+dt);
516  }
517  else
518  {
519  Set<Devs<X,T>*> components;
520  model->typeIsNetwork()->getComponents(components);
521  typename Set<Devs<X,T>*>::iterator iter = components.begin();
522  for (; iter != components.end(); iter++)
523  {
524  schedule(*iter,t);
525  }
526  }
527 }
528 
529 template <class X, class T>
530 void Simulator<X,T>::inject_event(Atomic<X,T>* model, X& value)
531 {
532  if (model->x == NULL)
533  {
534  if (model->y == NULL)
535  activated.insert(model);
536  model->x = io_pool.make_obj();
537  }
538  model->x->insert(value);
539 }
540 
541 template <class X, class T>
542 void Simulator<X,T>::route(Network<X,T>* parent, Devs<X,T>* src, X& x)
543 {
544  // Notify event listeners if this is an output event
545  if (parent != src && (lps == NULL || lps->out_flag != RESTORING_OUTPUT))
546  this->notify_output_listeners(src,x,sched.minPriority());
547  // No one to do the routing, so return
548  if (parent == NULL) return;
549  // Compute the set of receivers for this value
550  Bag<Event<X,T> >* recvs = recv_pool.make_obj();
551  parent->route(x,src,*recvs);
552  // Deliver the event to each of its targets
553  Atomic<X,T>* amodel = NULL;
554  typename Bag<Event<X,T> >::iterator recv_iter = recvs->begin();
555  for (; recv_iter != recvs->end(); recv_iter++)
556  {
557  // Check for self-influencing error condition
558  if (src == (*recv_iter).model)
559  {
560  exception err("Model tried to influence self",src);
561  throw err;
562  }
567  amodel = (*recv_iter).model->typeIsAtomic();
568  if (amodel != NULL)
569  {
570  // Inject it only if it is assigned to our processor
571  if (lps == NULL || amodel->getProc() == lps->lp->getID())
572  inject_event(amodel,(*recv_iter).value);
573  // Otherwise tell the lp about it
574  else if (lps->out_flag != RESTORING_OUTPUT)
575  lps->lp->notifyInput(amodel,(*recv_iter).value);
576  }
577  // if this is an external output from the parent model
578  else if ((*recv_iter).model == parent)
579  {
580  route(parent->getParent(),parent,(*recv_iter).value);
581  }
582  // otherwise it is an input to a coupled model
583  else
584  {
585  route((*recv_iter).model->typeIsNetwork(),
586  (*recv_iter).model,(*recv_iter).value);
587  }
588  }
589  recvs->clear();
590  recv_pool.destroy_obj(recvs);
591 }
592 
593 template <class X, class T>
594 void Simulator<X,T>::exec_event(Atomic<X,T>* model, T t)
595 {
596  if (!manage_lookahead_data(model)) return;
597  // Internal event
598  if (model->x == NULL)
599  model->delta_int();
600  // Confluent event
601  else if (model->y != NULL)
602  model->delta_conf(*(model->x));
603  // External event
604  else
605  model->delta_ext(t-model->tL,*(model->x));
606  // Notify any listeners
607  this->notify_state_listeners(model,t);
608  // Check for a model transition
609  if (model->model_transition() && model->getParent() != NULL)
610  {
611  model_func_eval_set.insert(model->getParent());
612  }
613 }
614 
615 template <class X, class T>
616 void Simulator<X,T>::getAllChildren(Network<X,T>* model, Set<Devs<X,T>*>& s)
617 {
618  Set<Devs<X,T>*> tmp;
619  // Get the component set
620  model->getComponents(tmp);
621  // Add all of the local level elements to s
622  s.insert(tmp.begin(),tmp.end());
623  // Find the components of type network and update s recursively
624  typename Set<Devs<X,T>*>::iterator iter;
625  for (iter = tmp.begin(); iter != tmp.end(); iter++)
626  {
627  if ((*iter)->typeIsNetwork() != NULL)
628  {
629  getAllChildren((*iter)->typeIsNetwork(),s);
630  }
631  }
632 }
633 
634 template <class X, class T>
636 {
637  // Clean up the models with stale IO
638  typename Bag<Atomic<X,T>*>::iterator iter;
639  for (iter = activated.begin(); iter != activated.end(); iter++)
640  {
641  clean_up(*iter);
642  }
643 }
644 
645 template <class X, class T>
646 Simulator<X,T>::Simulator(LogicalProcess<X,T>* lp):
647  AbstractSimulator<X,T>()
648 {
649  lps = new lp_support;
650  lps->lp = lp;
651  lps->look_ahead = false;
652  lps->stop_forced = false;
653  lps->out_flag = OUTPUT_OK;
654 }
655 
656 template <class X, class T>
658 {
659  if (lps == NULL)
660  {
661  adevs::exception err("tried to lookahead without lp support");
662  throw err;
663  }
664  lps->look_ahead = true;
665  if (!activated.empty())
666  lps->out_flag = OUTPUT_NOT_OK;
667 }
668 
669 template <class X, class T>
671 {
672  execNextEvent();
673 }
674 
675 template <class X, class T>
677 {
678  if (lps == NULL) return;
679  typename Bag<Atomic<X,T>*>::iterator iter = lps->to_restore.begin();
680  for (; iter != lps->to_restore.end(); iter++)
681  {
682  (*iter)->endLookahead();
683  schedule(*iter,(*iter)->tL_cp);
684  (*iter)->tL_cp = adevs_sentinel<T>();
685  assert((*iter)->x == NULL);
686  assert((*iter)->y == NULL);
687  }
688  lps->to_restore.clear();
689  assert(activated.empty());
690  if (lps->out_flag == OUTPUT_NOT_OK)
691  {
692  lps->out_flag = RESTORING_OUTPUT;
693  computeNextOutput();
694  lps->out_flag = OUTPUT_OK;
695  }
696  lps->look_ahead = false;
697  lps->stop_forced = false;
698 }
699 
700 template <class X, class T>
702 {
703  if (lps == NULL) return true;
704  if (lps->look_ahead && model->tL_cp < adevs_zero<T>())
705  {
706  lps->to_restore.insert(model);
707  model->tL_cp = model->tL;
708  try
709  {
710  model->beginLookahead();
711  }
712  catch(method_not_supported_exception err)
713  {
714  lps->stop_forced = true;
715  }
716  }
717  return !(lps->stop_forced);
718 }
719 
720 } // End of namespace
721 
722 #endif
Atomic< X, T > * typeIsAtomic()
Returns a pointer to this model.
Definition: adevs_models.h:255
Definition: adevs_models.h:49
Definition: adevs_abstract_simulator.h:45
Definition: adevs_set.h:42
void execNextEvent()
Execute the simulation cycle at time nextEventTime()
Definition: adevs_simulator.h:82
void beginLookahead()
Definition: adevs_simulator.h:657
void lookNextEvent()
Definition: adevs_simulator.h:670
void computeNextOutput()
Definition: adevs_simulator.h:300
Definition: adevs_models.h:46
void computeNextState(Bag< Event< X, T > > &input, T t)
Definition: adevs_simulator.h:309
void clear()
Remove all of the elements from the bag.
Definition: adevs_bag.h:144
virtual void gc_output(Bag< X > &g)=0
void addModel(Atomic< X, T > *model)
Definition: adevs_simulator.h:120
iterator begin() const
Get an iterator pointing to the first element in the bag.
Definition: adevs_bag.h:128
Definition: adevs_exception.h:43
Definition: adevs_models.h:48
iterator end() const
Get an iterator to the end of the bag (i.e., just after the last element)
Definition: adevs_bag.h:130
virtual Network< X, T > * typeIsNetwork()
Definition: adevs_models.h:81
virtual bool model_transition()
Definition: adevs_models.h:110
void set_assign_diff(Bag< T > &result, const Set< T > &A, const Set< T > &B)
Set difference operator. Returns the set A-B.
Definition: adevs_set.h:48
virtual void beginLookahead()
Definition: adevs_models.h:240
T nextEventTime()
Definition: adevs_simulator.h:77
void execUntil(T tend)
Execute until nextEventTime() > tend.
Definition: adevs_simulator.h:88
virtual Atomic< X, T > * typeIsAtomic()
Returns NULL if this is not an atomic model; returns itself otherwise.
Definition: adevs_models.h:83
~Simulator()
Definition: adevs_simulator.h:635
Definition: adevs_models.h:63
Definition: adevs_models.h:142
void endLookahead()
Definition: adevs_simulator.h:676
Definition: adevs_models.h:47
Simulator(Devs< X, T > *model)
Definition: adevs_simulator.h:66
Definition: adevs_exception.h:99
const Network< X, T > * getParent() const
Definition: adevs_models.h:88
Definition: adevs_bag.h:45