• Main Page
  • Classes
  • Files
  • File List

/home/rotten/Code/adevs/trunk/include/adevs_simulator.h

00001 /***************
00002 Copyright (C) 2000-2010 by James Nutaro
00003 
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2 of the License, or (at your option) any later version.
00008 
00009 This library is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 Bugs, comments, and questions can be sent to nutaro@gmail.com
00019 ***************/
00020 #ifndef __adevs_simulator_h_
00021 #define __adevs_simulator_h_
00022 #include "adevs_abstract_simulator.h"
00023 #include "adevs_models.h"
00024 #include "adevs_event_listener.h"
00025 #include "adevs_sched.h"
00026 #include "adevs_bag.h"
00027 #include "adevs_set.h"
00028 #include "object_pool.h"
00029 #include "adevs_lp.h"
00030 #include <cassert>
00031 #include <cstdlib>
00032 #include <iostream>
00033 #include <vector>
00034 
00035 namespace adevs
00036 {
00037 
00044 template <class X> class Simulator:
00045         public AbstractSimulator<X>
00046 {
00047         public:
00054                 Simulator(Devs<X>* model):
00055                         AbstractSimulator<X>(),lp(NULL)
00056                 {
00057                         schedule(model,0.0);
00058                 }
00063                 double nextEventTime()
00064                 {
00065                         return sched.minPriority();
00066                 }
00068                 void execNextEvent()
00069                 {
00070                         computeNextOutput();
00071                         computeNextState(bogus_input,sched.minPriority());
00072                 }
00074                 void execUntil(double tend)
00075                 {
00076                         while (nextEventTime() <= tend && nextEventTime() < DBL_MAX)
00077                                 execNextEvent();
00078                 }
00084                 void computeNextOutput();
00093                 void computeNextState(Bag<Event<X> >& input, double t);
00099                 ~Simulator();
00104                 void addModel(Atomic<X>* model) 
00105                 {
00106                         schedule(model,0.0);
00107                 }
00112                 Simulator(LogicalProcess<X>* lp):
00113                         AbstractSimulator<X>(),lp(lp)
00114                 {
00115                 }
00116         private:
00117                 // The processor that this simulator works for, or NULL if no simulator
00118                 LogicalProcess<X>* lp;
00119                 // Bogus input bag for execNextEvent() method
00120                 Bag<Event<X> > bogus_input;
00121                 // The event schedule
00122                 Schedule<X> sched;
00123                 // List of imminent models
00124                 Bag<Atomic<X>*> imm;
00125                 // List of models activated by input
00126                 Bag<Atomic<X>*> activated;
00127                 // Pools of preallocated, commonly used objects
00128                 object_pool<Bag<X> > io_pool;
00129                 object_pool<Bag<Event<X> > > recv_pool;
00130                 // Sets for computing structure changes.
00131                 Bag<Devs<X>*> added;
00132                 Bag<Devs<X>*> removed;
00133                 Set<Devs<X>*> next;
00134                 Set<Devs<X>*> prev;
00135                 // Model transition functions are evaluated from the bottom up!
00136                 struct bottom_to_top_depth_compare
00137                 {
00138                         bool operator()(const Network<X>* m1, const Network<X>* m2) const
00139                         {
00140                                 unsigned long int d1 = 0, d2 = 0;
00141                                 // Compute depth of m1
00142                                 const Network<X>* m = m1->getParent();
00143                                 while (m != NULL) 
00144                                 {
00145                                         d1++;
00146                                         m = m->getParent();
00147                                 }
00148                                 // Compute depth of m2
00149                                 m = m2->getParent();
00150                                 while (m != NULL)
00151                                 {
00152                                         d2++;
00153                                         m = m->getParent();
00154                                 }
00155                                 // Models at the same depth are sorted by name
00156                                 if (d1 == d2) return m1 < m2;
00157                                 // Otherwise, sort by depth
00158                                 return d1 > d2;
00159                         }
00160                 };
00161                 struct top_to_bottom_depth_compare
00162                 {
00163                         bool operator()(const Devs<X>* m1, const Devs<X>* m2) const
00164                         {
00165                                 unsigned long int d1 = 0, d2 = 0;
00166                                 // Compute depth of m1
00167                                 const Network<X>* m = m1->getParent();
00168                                 while (m != NULL) 
00169                                 {
00170                                         d1++;
00171                                         m = m->getParent();
00172                                 }
00173                                 // Compute depth of m2
00174                                 m = m2->getParent();
00175                                 while (m != NULL)
00176                                 {
00177                                         d2++;
00178                                         m = m->getParent();
00179                                 }
00180                                 // Models at the same depth are sorted by name
00181                                 if (d1 == d2) return m1 < m2;
00182                                 // Otherwise, sort by depth
00183                                 return d1 < d2;
00184                         }
00185                 };
00186                 std::set<Network<X>*,bottom_to_top_depth_compare> model_func_eval_set;
00187                 std::set<Devs<X>*,top_to_bottom_depth_compare> sorted_removed;
00192                 void schedule(Devs<X>* model, double t);
00194                 void route(Network<X>* parent, Devs<X>* src, X& x);
00199                 void inject_event(Atomic<X>* model, X& value);
00204                 void unschedule_model(Devs<X>* model);
00210                 void clean_up(Devs<X>* model);
00216                 void exec_event(Atomic<X>* model, bool internal, double t);
00220                 void getAllChildren(Network<X>* model, Set<Devs<X>*>& s);
00221 };
00222 
00223 template <class X>
00224 void Simulator<X>::computeNextOutput()
00225 {
00226         // If the imminent set is up to date, then just return
00227         if (imm.empty() == false) return;
00228         // Get the imminent models from the schedule. This sets the active flags.
00229         sched.getImminent(imm);
00230         // Compute output functions and route the events. The bags of output
00231         // are held for garbage collection at a later time.
00232         for (typename Bag<Atomic<X>*>::iterator imm_iter = imm.begin(); 
00233                 imm_iter != imm.end(); imm_iter++)
00234         {
00235                 Atomic<X>* model = *imm_iter;
00236                 // If the output for this model has already been computed, then skip it
00237                 if (model->y == NULL)
00238                 {
00239                         model->y = io_pool.make_obj();
00240                         model->output_func(*(model->y));
00241                         // Route each event in y
00242                         for (typename Bag<X>::iterator y_iter = model->y->begin(); 
00243                         y_iter != model->y->end(); y_iter++)
00244                         {
00245                                 route(model->getParent(),model,*y_iter);
00246                         }
00247                 }
00248         }
00249 }
00250 
00251 template <class X>
00252 void Simulator<X>::computeNextState(Bag<Event<X> >& input, double t)
00253 {
00254         // Clean up if there was a previous IO calculation
00255         if (t < sched.minPriority())
00256         {
00257                 typename Bag<Atomic<X>*>::iterator iter;
00258                 for (iter = activated.begin(); iter != activated.end(); iter++)
00259                 {
00260                         clean_up(*iter);
00261                 }
00262                 activated.clear();
00263                 for (iter = imm.begin(); iter != imm.end(); iter++)
00264                 {
00265                         clean_up(*iter);
00266                 }
00267                 imm.clear();
00268         }
00269         // Otherwise, if the internal IO needs to be computed, do it
00270         else if (t == sched.minPriority() && imm.empty())
00271         {
00272                 computeNextOutput();
00273         }
00274         // Apply the injected inputs
00275         for (typename Bag<Event<X> >::iterator iter = input.begin(); 
00276         iter != input.end(); iter++)
00277         {
00278                 Atomic<X>* amodel = (*iter).model->typeIsAtomic();
00279                 if (amodel != NULL)
00280                 {
00281                         inject_event(amodel,(*iter).value);
00282                 }
00283                 else
00284                 {
00285                         route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value);
00286                 }
00287         }
00288         /*
00289         Compute the states of atomic models.  Store Network models that need to have
00290         their model transition function evaluated in a
00291         special container that will be used when the structure changes are
00292         computed (see exec_event(.)).
00293         */
00294         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 
00295         iter != imm.end(); iter++)
00296         {
00297                 exec_event(*iter,true,t); // Internal and confluent transitions
00298         }
00299         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 
00300         iter != activated.end(); iter++)
00301         {
00302                 exec_event(*iter,false,t); // External transitions
00303         }
00310         if (model_func_eval_set.empty() == false)
00311         {
00312                 while (!model_func_eval_set.empty())
00313                 {
00314                         Network<X>* network_model = *(model_func_eval_set.begin());
00315                         getAllChildren(network_model,prev);
00316                         if (network_model->model_transition() && network_model->getParent() != NULL)
00317                         {
00318                                 model_func_eval_set.insert(network_model->getParent());
00319                         }
00320                         getAllChildren(network_model,next);
00321                         model_func_eval_set.erase(network_model);
00322                 }
00323                 // Find the set of models that were added.
00324                 set_assign_diff(added,next,prev);
00325                 // Find the set of models that were removed
00326                 set_assign_diff(removed,prev,next);
00327                 // Intersection of added and removed is always empty, so no need to look
00328                 // for models in both (an earlier version of the code did this).
00329                 next.clear();
00330                 prev.clear();
00337                 for (typename Bag<Devs<X>*>::iterator iter = added.begin(); 
00338                         iter != added.end(); iter++)
00339                 {
00340                         schedule(*iter,t);
00341                 }
00342                 // Done with the additions
00343                 added.clear();
00344                 // Remove the models that are in the removed set.
00345                 for (typename Bag<Devs<X>*>::iterator iter = removed.begin(); 
00346                         iter != removed.end(); iter++)
00347                 {
00348                         clean_up(*iter);
00349                         unschedule_model(*iter);
00350                         sorted_removed.insert(*iter); // Add to a sorted remove set for deletion
00351                 }
00352                 // Done with the unsorted remove set
00353                 removed.clear();
00354                 // Delete the sorted removed models
00355                 while (!sorted_removed.empty())
00356                 {
00357                         // Get the model to erase
00358                         Devs<X>* model_to_remove = *(sorted_removed.begin());
00363                         if (model_to_remove->typeIsNetwork() != NULL)
00364                         {
00365                                 getAllChildren(model_to_remove->typeIsNetwork(),prev);
00366                                 for (typename Set<Devs<X>*>::iterator iter = prev.begin(); 
00367                                         iter != prev.end(); iter++)
00368                                 {
00369                                         sorted_removed.erase(*iter);
00370                                 }
00371                                 prev.clear();
00372                         }
00373                         // Remove the model
00374                         sorted_removed.erase(sorted_removed.begin());
00375                         // Delete the model and its children
00376                         delete model_to_remove;
00377                 }
00378                 // Removed sets should be empty now
00379                 assert(prev.empty());
00380                 assert(sorted_removed.empty());
00381         } // End of the structure change
00382         // Cleanup and reschedule models that changed state in this iteration
00383         // and survived the structure change phase.
00384         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); // Schedule the imminents
00385         iter != imm.end(); iter++)
00386         {
00387                 clean_up(*iter);
00388                 schedule(*iter,t);
00389         }
00390         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); // Schedule the activated
00391         iter != activated.end(); iter++)
00392         {
00393                 clean_up(*iter);
00394                 schedule(*iter,t);
00395         }
00396         // Empty the bags
00397         imm.clear();
00398         activated.clear();
00399 }
00400 
00401 template <class X>
00402 void Simulator<X>::clean_up(Devs<X>* model)
00403 {
00404         Atomic<X>* amodel = model->typeIsAtomic();
00405         if (amodel != NULL)
00406         {
00407                 amodel->active = false;
00408                 if (amodel->x != NULL)
00409                 {
00410                         amodel->x->clear();
00411                         io_pool.destroy_obj(amodel->x);
00412                         amodel->x = NULL;
00413                 }
00414                 if (amodel->y != NULL)
00415                 {
00416                         amodel->gc_output(*(amodel->y));
00417                         amodel->y->clear();
00418                         io_pool.destroy_obj(amodel->y);
00419                         amodel->y = NULL;
00420                 }
00421         }
00422         else
00423         {
00424                 Set<Devs<X>*> components;
00425                 model->typeIsNetwork()->getComponents(components);
00426                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00427                 iter != components.end(); iter++)
00428                 {
00429                         clean_up(*iter);
00430                 }
00431         }
00432 }
00433 
00434 template <class X>
00435 void Simulator<X>::unschedule_model(Devs<X>* model)
00436 {
00437         if (model->typeIsAtomic() != NULL)
00438         {
00439                 sched.schedule(model->typeIsAtomic(),DBL_MAX);
00440                 imm.erase(model->typeIsAtomic());
00441                 activated.erase(model->typeIsAtomic());
00442         }
00443         else
00444         {
00445                 Set<Devs<X>*> components;
00446                 model->typeIsNetwork()->getComponents(components);
00447                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00448                 iter != components.end(); iter++)
00449                 {
00450                         unschedule_model(*iter);
00451                 }
00452         }
00453 }
00454 
00455 template <class X>
00456 void Simulator<X>::schedule(Devs<X>* model, double t)
00457 {
00458         Atomic<X>* a = model->typeIsAtomic();
00459         if (a != NULL)
00460         {
00461                 a->tL = t;
00462                 double dt = a->ta();
00463                 if (dt < 0.0)
00464                 {
00465                         exception err("Negative time advance",a);
00466                         throw err;
00467                 }
00468                 if (dt == DBL_MAX)
00469                         sched.schedule(a,DBL_MAX);
00470                 else
00471                         sched.schedule(a,t+dt);
00472         }
00473         else
00474         {
00475                 Set<Devs<X>*> components;
00476                 model->typeIsNetwork()->getComponents(components);
00477                 typename Set<Devs<X>*>::iterator iter = components.begin();
00478                 for (; iter != components.end(); iter++)
00479                 {
00480                         schedule(*iter,t);
00481                 }
00482         }
00483 }
00484 
00485 template <class X>
00486 void Simulator<X>::inject_event(Atomic<X>* model, X& value)
00487 {
00488         if (model->active == false)
00489         {
00490                 model->active = true;
00491                 activated.insert(model);
00492         }
00493         if (model->x == NULL)
00494         {
00495                 model->x = io_pool.make_obj();
00496         }
00497         model->x->insert(value);
00498 }
00499 
00500 template <class X>
00501 void Simulator<X>::route(Network<X>* parent, Devs<X>* src, X& x)
00502 {
00503         // Notify event listeners if this is an output event
00504         if (parent != src)
00505                 notify_output_listeners(src,x,sched.minPriority());
00506         // No one to do the routing, so return
00507         if (parent == NULL) return;
00508         // Compute the set of receivers for this value
00509         Bag<Event<X> >* recvs = recv_pool.make_obj();
00510         parent->route(x,src,*recvs);
00511         // Deliver the event to each of its targets
00512         Atomic<X>* amodel = NULL;
00513         typename Bag<Event<X> >::iterator recv_iter = recvs->begin();
00514         for (; recv_iter != recvs->end(); recv_iter++)
00515         {
00516                 // Check for self-influencing error condition
00517                 if (src == (*recv_iter).model)
00518                 {
00519                         exception err("Model tried to influence self",src);
00520                         throw err;
00521                 }
00526                 amodel = (*recv_iter).model->typeIsAtomic();
00527                 if (amodel != NULL)
00528                 {
00529                         // Inject it only if it is assigned to our processor
00530                         if (lp == NULL || amodel->getProc() == lp->getID())
00531                                 inject_event(amodel,(*recv_iter).value);
00532                         // Otherwise tell the lp about it
00533                         else lp->notifyInput(amodel,(*recv_iter).value);
00534                 }
00535                 // if this is an external output from the parent model
00536                 else if ((*recv_iter).model == parent)
00537                 {
00538                         route(parent->getParent(),parent,(*recv_iter).value);
00539                 }
00540                 // otherwise it is an input to a coupled model
00541                 else
00542                 {
00543                         route((*recv_iter).model->typeIsNetwork(),
00544                         (*recv_iter).model,(*recv_iter).value);
00545                 }
00546         }
00547         recvs->clear();
00548         recv_pool.destroy_obj(recvs);
00549 }
00550 
00551 template <class X>
00552 void Simulator<X>::exec_event(Atomic<X>* model, bool internal, double t)
00553 {
00554         // Compute the state change
00555         if (model->x == NULL)
00556         {
00557                 model->delta_int();
00558         }
00559         else if (internal)
00560         {
00561                 model->delta_conf(*(model->x));
00562         }
00563         else
00564         {
00565                 model->delta_ext(t-model->tL,*(model->x));
00566         }
00567         // Notify any listeners
00568         notify_state_listeners(model,t);
00569         // Check for a model transition
00570         if (model->model_transition() && model->getParent() != NULL)
00571         {
00572                 model_func_eval_set.insert(model->getParent());
00573         }
00574 }
00575 
00576 template <class X>
00577 void Simulator<X>::getAllChildren(Network<X>* model, Set<Devs<X>*>& s)
00578 {
00579         Set<Devs<X>*> tmp;
00580         // Get the component set
00581         model->getComponents(tmp);
00582         // Find the components of type network and update s recursively
00583         typename Set<Devs<X>*>::iterator iter;
00584         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00585         {
00586                 if ((*iter)->typeIsNetwork() != NULL)
00587                 {
00588                         getAllChildren((*iter)->typeIsNetwork(),s);
00589                 }
00590         }
00591         // Add all of the local level elements to s
00592         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00593         {
00594                 s.insert(*iter);
00595         }
00596 }
00597 
00598 template <class X>
00599 Simulator<X>::~Simulator()
00600 {
00601         // Clean up the models with stale IO
00602         typename Bag<Atomic<X>*>::iterator imm_iter;
00603         for (imm_iter = imm.begin(); imm_iter != imm.end(); imm_iter++)
00604         {
00605                 clean_up(*imm_iter);
00606         }
00607         for (imm_iter = activated.begin(); imm_iter != activated.end(); imm_iter++)
00608         {
00609                 clean_up(*imm_iter);
00610         }
00611 }
00612 
00613 } // End of namespace
00614 
00615 #endif

Generated on Sun Jan 23 2011 for adevs by  doxygen 1.7.1