adevs
|
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>(),lps(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); 00124 void beginLookahead(); 00129 void endLookahead(); 00136 void lookNextEvent(); 00137 private: 00138 typedef enum { OUTPUT_OK, OUTPUT_NOT_OK, RESTORING_OUTPUT } OutputStatus; 00139 // Structure to support parallel computing by a logical process 00140 struct lp_support 00141 { 00142 // The processor that this simulator works for 00143 LogicalProcess<X>* lp; 00144 bool look_ahead, stop_forced; 00145 OutputStatus out_flag; 00146 Bag<Atomic<X>*> to_restore; 00147 }; 00148 // This is NULL if the simulator is not supporting a logical process 00149 lp_support* lps; 00150 // Bogus input bag for execNextEvent() method 00151 Bag<Event<X> > bogus_input; 00152 // The event schedule 00153 Schedule<X> sched; 00154 // List of imminent models 00155 Bag<Atomic<X>*> imm; 00156 // List of models activated by input 00157 Bag<Atomic<X>*> activated; 00158 // Pools of preallocated, commonly used objects 00159 object_pool<Bag<X> > io_pool; 00160 object_pool<Bag<Event<X> > > recv_pool; 00161 // Sets for computing structure changes. 00162 Bag<Devs<X>*> added; 00163 Bag<Devs<X>*> removed; 00164 Set<Devs<X>*> next; 00165 Set<Devs<X>*> prev; 00166 // Model transition functions are evaluated from the bottom up! 00167 struct bottom_to_top_depth_compare 00168 { 00169 bool operator()(const Network<X>* m1, const Network<X>* m2) const 00170 { 00171 unsigned long int d1 = 0, d2 = 0; 00172 // Compute depth of m1 00173 const Network<X>* m = m1->getParent(); 00174 while (m != NULL) 00175 { 00176 d1++; 00177 m = m->getParent(); 00178 } 00179 // Compute depth of m2 00180 m = m2->getParent(); 00181 while (m != NULL) 00182 { 00183 d2++; 00184 m = m->getParent(); 00185 } 00186 // Models at the same depth are sorted by name 00187 if (d1 == d2) return m1 < m2; 00188 // Otherwise, sort by depth 00189 return d1 > d2; 00190 } 00191 }; 00192 struct top_to_bottom_depth_compare 00193 { 00194 bool operator()(const Devs<X>* m1, const Devs<X>* m2) const 00195 { 00196 unsigned long int d1 = 0, d2 = 0; 00197 // Compute depth of m1 00198 const Network<X>* m = m1->getParent(); 00199 while (m != NULL) 00200 { 00201 d1++; 00202 m = m->getParent(); 00203 } 00204 // Compute depth of m2 00205 m = m2->getParent(); 00206 while (m != NULL) 00207 { 00208 d2++; 00209 m = m->getParent(); 00210 } 00211 // Models at the same depth are sorted by name 00212 if (d1 == d2) return m1 < m2; 00213 // Otherwise, sort by depth 00214 return d1 < d2; 00215 } 00216 }; 00217 std::set<Network<X>*,bottom_to_top_depth_compare> model_func_eval_set; 00218 std::set<Devs<X>*,top_to_bottom_depth_compare> sorted_removed; 00223 void schedule(Devs<X>* model, double t); 00225 void route(Network<X>* parent, Devs<X>* src, X& x); 00231 void inject_event(Atomic<X>* model, X& value); 00236 void unschedule_model(Devs<X>* model); 00242 void clean_up(Devs<X>* model); 00249 void exec_event(Atomic<X>* model, bool internal, double t); 00253 void getAllChildren(Network<X>* model, Set<Devs<X>*>& s); 00259 bool manage_lookahead_data(Atomic<X>* model); 00260 }; 00261 00262 template <class X> 00263 void Simulator<X>::computeNextOutput() 00264 { 00265 // If the imminent set is up to date, then just return 00266 if (imm.empty() == false) return; 00267 // Get the imminent models from the schedule. This sets the active flags. 00268 sched.getImminent(imm); 00269 // Compute output functions and route the events. The bags of output 00270 // are held for garbage collection at a later time. 00271 for (typename Bag<Atomic<X>*>::iterator imm_iter = imm.begin(); 00272 imm_iter != imm.end(); imm_iter++) 00273 { 00274 Atomic<X>* model = *imm_iter; 00275 // If the output for this model has already been computed, then skip it 00276 if (model->y == NULL) 00277 { 00278 model->y = io_pool.make_obj(); 00279 model->output_func(*(model->y)); 00280 // Route each event in y 00281 for (typename Bag<X>::iterator y_iter = model->y->begin(); 00282 y_iter != model->y->end(); y_iter++) 00283 { 00284 route(model->getParent(),model,*y_iter); 00285 } 00286 } 00287 } 00288 } 00289 00290 template <class X> 00291 void Simulator<X>::computeNextState(Bag<Event<X> >& input, double t) 00292 { 00293 // Clean up if there was a previous IO calculation 00294 if (t < sched.minPriority()) 00295 { 00296 typename Bag<Atomic<X>*>::iterator iter; 00297 for (iter = activated.begin(); iter != activated.end(); iter++) 00298 { 00299 clean_up(*iter); 00300 } 00301 activated.clear(); 00302 for (iter = imm.begin(); iter != imm.end(); iter++) 00303 { 00304 clean_up(*iter); 00305 } 00306 imm.clear(); 00307 } 00308 // Otherwise, if the internal IO needs to be computed, do it 00309 else if (t == sched.minPriority() && imm.empty()) 00310 { 00311 computeNextOutput(); 00312 } 00313 // Apply the injected inputs 00314 for (typename Bag<Event<X> >::iterator iter = input.begin(); 00315 iter != input.end(); iter++) 00316 { 00317 Atomic<X>* amodel = (*iter).model->typeIsAtomic(); 00318 if (amodel != NULL) 00319 { 00320 inject_event(amodel,(*iter).value); 00321 } 00322 else 00323 { 00324 route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value); 00325 } 00326 } 00327 /* 00328 Compute the states of atomic models. Store Network models that 00329 need to have their model transition function evaluated in a 00330 special container that will be used when the structure changes are 00331 computed (see exec_event(.)). 00332 */ 00333 for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 00334 iter != imm.end(); iter++) 00335 { 00336 exec_event(*iter,true,t); // Internal and confluent transitions 00337 } 00338 for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 00339 iter != activated.end(); iter++) 00340 { 00341 exec_event(*iter,false,t); // External transitions 00342 } 00349 if (model_func_eval_set.empty() == false) 00350 { 00351 while (!model_func_eval_set.empty()) 00352 { 00353 Network<X>* network_model = *(model_func_eval_set.begin()); 00354 getAllChildren(network_model,prev); 00355 if (network_model->model_transition() && 00356 network_model->getParent() != NULL) 00357 { 00358 model_func_eval_set.insert(network_model->getParent()); 00359 } 00360 getAllChildren(network_model,next); 00361 model_func_eval_set.erase(network_model); 00362 } 00363 // Find the set of models that were added. 00364 set_assign_diff(added,next,prev); 00365 // Find the set of models that were removed 00366 set_assign_diff(removed,prev,next); 00367 // Intersection of added and removed is always empty, so no need to look 00368 // for models in both (an earlier version of the code did this). 00369 next.clear(); 00370 prev.clear(); 00377 for (typename Bag<Devs<X>*>::iterator iter = added.begin(); 00378 iter != added.end(); iter++) 00379 { 00380 schedule(*iter,t); 00381 } 00382 // Done with the additions 00383 added.clear(); 00384 // Remove the models that are in the removed set. 00385 for (typename Bag<Devs<X>*>::iterator iter = removed.begin(); 00386 iter != removed.end(); iter++) 00387 { 00388 clean_up(*iter); 00389 unschedule_model(*iter); 00390 // Add to a sorted remove set for deletion 00391 sorted_removed.insert(*iter); 00392 } 00393 // Done with the unsorted remove set 00394 removed.clear(); 00395 // Delete the sorted removed models 00396 while (!sorted_removed.empty()) 00397 { 00398 // Get the model to erase 00399 Devs<X>* model_to_remove = *(sorted_removed.begin()); 00404 if (model_to_remove->typeIsNetwork() != NULL) 00405 { 00406 getAllChildren(model_to_remove->typeIsNetwork(),prev); 00407 for (typename Set<Devs<X>*>::iterator iter = prev.begin(); 00408 iter != prev.end(); iter++) 00409 { 00410 sorted_removed.erase(*iter); 00411 } 00412 prev.clear(); 00413 } 00414 // Remove the model 00415 sorted_removed.erase(sorted_removed.begin()); 00416 // Delete the model and its children 00417 delete model_to_remove; 00418 } 00419 // Removed sets should be empty now 00420 assert(prev.empty()); 00421 assert(sorted_removed.empty()); 00422 } // End of the structure change 00423 // Cleanup and reschedule models that changed state in this iteration 00424 // and survived the structure change phase. 00425 for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 00426 iter != imm.end(); iter++) // Schedule the imminents 00427 { 00428 clean_up(*iter); 00429 schedule(*iter,t); 00430 } 00431 // Schedule the activated 00432 for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 00433 iter != activated.end(); iter++) 00434 { 00435 clean_up(*iter); 00436 schedule(*iter,t); 00437 } 00438 // Empty the bags 00439 imm.clear(); 00440 activated.clear(); 00441 // If we are looking ahead, throw an exception if a stop was forced 00442 if (lps != NULL && lps->stop_forced) 00443 { 00444 lookahead_impossible_exception err; 00445 throw err; 00446 } 00447 } 00448 00449 template <class X> 00450 void Simulator<X>::clean_up(Devs<X>* model) 00451 { 00452 Atomic<X>* amodel = model->typeIsAtomic(); 00453 if (amodel != NULL) 00454 { 00455 amodel->active = false; 00456 if (amodel->x != NULL) 00457 { 00458 amodel->x->clear(); 00459 io_pool.destroy_obj(amodel->x); 00460 amodel->x = NULL; 00461 } 00462 if (amodel->y != NULL) 00463 { 00464 amodel->gc_output(*(amodel->y)); 00465 amodel->y->clear(); 00466 io_pool.destroy_obj(amodel->y); 00467 amodel->y = NULL; 00468 } 00469 } 00470 else 00471 { 00472 Set<Devs<X>*> components; 00473 model->typeIsNetwork()->getComponents(components); 00474 for (typename Set<Devs<X>*>::iterator iter = components.begin(); 00475 iter != components.end(); iter++) 00476 { 00477 clean_up(*iter); 00478 } 00479 } 00480 } 00481 00482 template <class X> 00483 void Simulator<X>::unschedule_model(Devs<X>* model) 00484 { 00485 if (model->typeIsAtomic() != NULL) 00486 { 00487 sched.schedule(model->typeIsAtomic(),DBL_MAX); 00488 imm.erase(model->typeIsAtomic()); 00489 activated.erase(model->typeIsAtomic()); 00490 } 00491 else 00492 { 00493 Set<Devs<X>*> components; 00494 model->typeIsNetwork()->getComponents(components); 00495 for (typename Set<Devs<X>*>::iterator iter = components.begin(); 00496 iter != components.end(); iter++) 00497 { 00498 unschedule_model(*iter); 00499 } 00500 } 00501 } 00502 00503 template <class X> 00504 void Simulator<X>::schedule(Devs<X>* model, double t) 00505 { 00506 Atomic<X>* a = model->typeIsAtomic(); 00507 if (a != NULL) 00508 { 00509 a->tL = t; 00510 double dt = a->ta(); 00511 if (dt < 0.0) 00512 { 00513 exception err("Negative time advance",a); 00514 throw err; 00515 } 00516 if (dt == DBL_MAX) 00517 sched.schedule(a,DBL_MAX); 00518 else 00519 sched.schedule(a,t+dt); 00520 } 00521 else 00522 { 00523 Set<Devs<X>*> components; 00524 model->typeIsNetwork()->getComponents(components); 00525 typename Set<Devs<X>*>::iterator iter = components.begin(); 00526 for (; iter != components.end(); iter++) 00527 { 00528 schedule(*iter,t); 00529 } 00530 } 00531 } 00532 00533 template <class X> 00534 void Simulator<X>::inject_event(Atomic<X>* model, X& value) 00535 { 00536 if (model->active == false) 00537 { 00538 model->active = true; 00539 activated.insert(model); 00540 } 00541 if (model->x == NULL) 00542 { 00543 model->x = io_pool.make_obj(); 00544 } 00545 model->x->insert(value); 00546 } 00547 00548 template <class X> 00549 void Simulator<X>::route(Network<X>* parent, Devs<X>* src, X& x) 00550 { 00551 // Notify event listeners if this is an output event 00552 if (parent != src && (lps == NULL || lps->out_flag != RESTORING_OUTPUT)) 00553 notify_output_listeners(src,x,sched.minPriority()); 00554 // No one to do the routing, so return 00555 if (parent == NULL) return; 00556 // Compute the set of receivers for this value 00557 Bag<Event<X> >* recvs = recv_pool.make_obj(); 00558 parent->route(x,src,*recvs); 00559 // Deliver the event to each of its targets 00560 Atomic<X>* amodel = NULL; 00561 typename Bag<Event<X> >::iterator recv_iter = recvs->begin(); 00562 for (; recv_iter != recvs->end(); recv_iter++) 00563 { 00564 // Check for self-influencing error condition 00565 if (src == (*recv_iter).model) 00566 { 00567 exception err("Model tried to influence self",src); 00568 throw err; 00569 } 00574 amodel = (*recv_iter).model->typeIsAtomic(); 00575 if (amodel != NULL) 00576 { 00577 // Inject it only if it is assigned to our processor 00578 if (lps == NULL || amodel->getProc() == lps->lp->getID()) 00579 inject_event(amodel,(*recv_iter).value); 00580 // Otherwise tell the lp about it 00581 else if (lps->out_flag != RESTORING_OUTPUT) 00582 lps->lp->notifyInput(amodel,(*recv_iter).value); 00583 } 00584 // if this is an external output from the parent model 00585 else if ((*recv_iter).model == parent) 00586 { 00587 route(parent->getParent(),parent,(*recv_iter).value); 00588 } 00589 // otherwise it is an input to a coupled model 00590 else 00591 { 00592 route((*recv_iter).model->typeIsNetwork(), 00593 (*recv_iter).model,(*recv_iter).value); 00594 } 00595 } 00596 recvs->clear(); 00597 recv_pool.destroy_obj(recvs); 00598 } 00599 00600 template <class X> 00601 void Simulator<X>::exec_event(Atomic<X>* model, bool internal, double t) 00602 { 00603 if (!manage_lookahead_data(model)) return; 00604 // Compute the state change 00605 if (model->x == NULL) 00606 { 00607 model->delta_int(); 00608 } 00609 else if (internal) 00610 { 00611 model->delta_conf(*(model->x)); 00612 } 00613 else 00614 { 00615 model->delta_ext(t-model->tL,*(model->x)); 00616 } 00617 // Notify any listeners 00618 notify_state_listeners(model,t); 00619 // Check for a model transition 00620 if (model->model_transition() && model->getParent() != NULL) 00621 { 00622 model_func_eval_set.insert(model->getParent()); 00623 } 00624 } 00625 00626 template <class X> 00627 void Simulator<X>::getAllChildren(Network<X>* model, Set<Devs<X>*>& s) 00628 { 00629 Set<Devs<X>*> tmp; 00630 // Get the component set 00631 model->getComponents(tmp); 00632 // Find the components of type network and update s recursively 00633 typename Set<Devs<X>*>::iterator iter; 00634 for (iter = tmp.begin(); iter != tmp.end(); iter++) 00635 { 00636 if ((*iter)->typeIsNetwork() != NULL) 00637 { 00638 getAllChildren((*iter)->typeIsNetwork(),s); 00639 } 00640 } 00641 // Add all of the local level elements to s 00642 for (iter = tmp.begin(); iter != tmp.end(); iter++) 00643 { 00644 s.insert(*iter); 00645 } 00646 } 00647 00648 template <class X> 00649 Simulator<X>::~Simulator() 00650 { 00651 // Clean up the models with stale IO 00652 typename Bag<Atomic<X>*>::iterator imm_iter; 00653 for (imm_iter = imm.begin(); imm_iter != imm.end(); imm_iter++) 00654 { 00655 clean_up(*imm_iter); 00656 } 00657 for (imm_iter = activated.begin(); imm_iter != activated.end(); imm_iter++) 00658 { 00659 clean_up(*imm_iter); 00660 } 00661 } 00662 00663 template <class X> 00664 Simulator<X>::Simulator(LogicalProcess<X>* lp): 00665 AbstractSimulator<X>() 00666 { 00667 lps = new lp_support; 00668 lps->lp = lp; 00669 lps->look_ahead = false; 00670 lps->stop_forced = false; 00671 lps->out_flag = OUTPUT_OK; 00672 } 00673 00674 template <class X> 00675 void Simulator<X>::beginLookahead() 00676 { 00677 if (lps == NULL) 00678 { 00679 adevs::exception err("tried to lookahead without lp support"); 00680 throw err; 00681 } 00682 lps->look_ahead = true; 00683 if (!imm.empty()) 00684 lps->out_flag = OUTPUT_NOT_OK; 00685 } 00686 00687 template <class X> 00688 void Simulator<X>::lookNextEvent() 00689 { 00690 execNextEvent(); 00691 } 00692 00693 template <class X> 00694 void Simulator<X>::endLookahead() 00695 { 00696 if (lps == NULL) return; 00697 typename Bag<Atomic<X>*>::iterator iter = lps->to_restore.begin(); 00698 for (; iter != lps->to_restore.end(); iter++) 00699 { 00700 (*iter)->endLookahead(); 00701 schedule(*iter,(*iter)->tL_cp); 00702 (*iter)->tL_cp = -1.0; 00703 assert((*iter)->x == NULL); 00704 assert((*iter)->y == NULL); 00705 } 00706 lps->to_restore.clear(); 00707 assert(imm.empty()); 00708 if (lps->out_flag == OUTPUT_NOT_OK) 00709 { 00710 lps->out_flag = RESTORING_OUTPUT; 00711 computeNextOutput(); 00712 lps->out_flag = OUTPUT_OK; 00713 } 00714 lps->look_ahead = false; 00715 lps->stop_forced = false; 00716 } 00717 00718 template <class X> 00719 bool Simulator<X>::manage_lookahead_data(Atomic<X>* model) 00720 { 00721 if (lps == NULL) return true; 00722 if (lps->look_ahead && model->tL_cp < 0.0) 00723 { 00724 lps->to_restore.insert(model); 00725 model->tL_cp = model->tL; 00726 try 00727 { 00728 model->beginLookahead(); 00729 } 00730 catch(method_not_supported_exception err) 00731 { 00732 lps->stop_forced = true; 00733 } 00734 } 00735 return !(lps->stop_forced); 00736 } 00737 00738 } // End of namespace 00739 00740 #endif