///////////////////////////////////////////////////////////////////////////// // run.cc // // SIMLIB version: 2.18 // Date: 2004-01-25 // // Copyright (c) 1991-2004 Petr Peringer // // This library is licensed under GNU Library GPL. See the file COPYING. // // // description: control of simulation // //////////////////////////////////////////////////////////////////////////// // interface //////////////////////////////////////////////////////////////////////////// #include "simlib.h" #include "internal.h" //////////////////////////////////////////////////////////////////////////// // implementation //////////////////////////////////////////////////////////////////////////// SIMLIB_IMPLEMENTATION //////////////////////////////////////////////////////////////////////////// // SIMLIB global variables ### move to extra module!!! // // SIMLIB_* --- internal variables // [A-Z]* --- user-level variables // unsigned SIMLIB_version = __SIMLIB__; // library version // time-related variables double SIMLIB_StartTime; // time of simulation start double SIMLIB_Time; // simulation time double SIMLIB_NextTime; // next-event time double SIMLIB_EndTime; // time of simulation end // read-only references to time variables // ASSERTION: StartTime <= Time <= NextTime <= EndTime const double & StartTime = SIMLIB_StartTime; // time of simulation start const double & Time = SIMLIB_Time; // simulation time const double & NextTime = SIMLIB_NextTime; // next-event time const double & EndTime = SIMLIB_EndTime; // time of simulation end // current entity pointer Entity *SIMLIB_Current = NULL; Entity *const &Current = SIMLIB_Current; // read-only reference // phase of simulation experiment SIMLIB_Phase_t SIMLIB_Phase = START; const SIMLIB_Phase_t & Phase = SIMLIB_Phase; // read-only reference //////////////////////////////////////////////////////////////////////////// // ETC... long SIMLIB_StepCount = 0; // ### for statistical purposes only //////////////////////////////////////////////////////////////////////////// // private module variables static bool StopFlag = false; // if set, stop simulation run //////////////////////////////////////////////////////////////////////////// // support for Delay blocks (internal) // DEFINE_HOOK(Delay); // called in Run() and SampleDelays() DEFINE_HOOK(DelayInit); // called in Init() // for explicit sampling void SampleDelays() { // used at step-wise changes !!!### CALL_HOOK(Delay); } // ZDelays: DEFINE_HOOK(ZDelayTimerInit); // called in Run() //////////////////////////////////////////////////////////////////////////// // support for Petri net simulator (CPN) (internal) // #ifdef PN_SUPPORT DEFINE_HOOK(PN1); // called in Run() DEFINE_HOOK(PN2); // called in Run() #endif //////////////////////////////////////////////////////////////////////////// // support for simulation interrupt (user-level) // DEFINE_HOOK(Break); // called in Run() void InstallBreak(void (*f)()) { // for user interface (in simlib.h) INSTALL_HOOK( Break, f ); } //////////////////////////////////////////////////////////////////////////// // support for Samplers (internal) // DEFINE_HOOK(SamplerAct); // called in Run() DEFINE_HOOK(SamplerInit); // called in Init() // temporary #ifdef -- remove with old implementation ### #ifdef NEW_WULIST //////////////////////////////////////////////////////////////////////////// // WUclear hook --- if non-empty WUlist, call init function // DEFINE_HOOK(WUclear); // should be in run.cc //////////////////////////////////////////////////////////////////////////// // SIMLIB_WUClear --- remove all items in WaitUntil list // void SIMLIB_WUClear() // should be removed -- ise CALL_HOOK instead { CALL_HOOK(WUclear); } //////////////////////////////////////////////////////////////////////////// // // DEFINE_HOOK(WUget_next); //////////////////////////////////////////////////////////////////////////// // SIMLIB_DoActions --- central calling of interruptable procedures // WARNING: SIMLIB_Current->_Run() should be called from this place only! void SIMLIB_DoActions() { // remove this: ########### if(flag) SIMLIB_internal_error(); do { SIMLIB_Current->_Run(); // perform event-dispatch SIMLIB_Current = 0; CALL_HOOK(WUget_next); // check and activate next in WUlist }while( SIMLIB_Current != 0 ); // remove this: ########### if(flag) SIMLIB_internal_error(); } #endif //////////////////////////////////////////////////////////////////////////// // Stop --- break of single simulation run // void Stop() { dprintf(("\n ********************* STOP *********************\n")); if( SIMLIB_Phase != SIMULATION ) // if runs a simulation experiment SIMLIB_error(SFunctionUseError); StopFlag = true; } //////////////////////////////////////////////////////////////////////////// // Abort --- end of simulation program // void Abort() { dprintf(("\n ********************* ABORT *********************\n")); SIMLIB_Phase = ERROREXIT; exit(1); // end of program, errorcode 1 } //////////////////////////////////////////////////////////////////////////// // SIMLIB_Init --- initialization of simulation system and some parts of // model; some checks // initialize: // - Time, StartTime, EndTime // - calendar (SQS) // - WaitUntilList // - existing continuous blocks, ... // - Delay blocks // void SIMLIB_Init(double T0, double T1, unsigned version) { dprintf(("\n\t ************************* Init(%g,%g) \n",T0,T1)); // first some checks if(version != SIMLIB_version) { // check versions dprintf(("\n SIMLIB library version %x.%02x ", SIMLIB_version >> 8, SIMLIB_version & 0xFF)); dprintf((" SIMLIB header version %x.%02x \n", version >> 8, version & 0xFF)); SIMLIB_error(InconsistentHeader); // exit program } if( SIMLIB_Phase == INITIALIZATION ) SIMLIB_error(TwiceInitError); if( SIMLIB_Phase == SIMULATION ) SIMLIB_error(InitInRunError); SIMLIB_Phase = INITIALIZATION; ///////////////////////////////////////////////////////////////// if( T0 < SIMLIB_MINTIME ) SIMLIB_error(InitError); if( T1 > SIMLIB_MAXTIME ) SIMLIB_error(InitError); if( T0 >= T1 ) SIMLIB_error(InitError); ///////////////////////////////////////////////////////////////// // set simulation parameters _SetTime(StartTime,T0); _SetTime(Time,T0); _SetTime(EndTime,T1); // set reasonable defaults for Step limits ??? // if not set by user first ### add flag to SetStep // MaxStep = tend/100; // MinStep = MaxStep/1000; // TODO: add SIMLIB_RunNumber++ // TODO: add real-time stderr/cerr output message for long computations? // on-demand print of "RunNumber:Time ETArun:minutes" each minute? // ADD list of functions to call: (dynamically!!!, priority) // something like atexit(): atInit, atRunStart, atRunEnd SQS::Clear(); // initialize calendar SIMLIB_WUClear(); // initialize WaitUntilList SIMLIB_ContinueInit(); // initialize status 1 ### CALL_HOOK(SamplerInit); // initialize all Samplers CALL_HOOK(DelayInit); // initialize all Delays } //////////////////////////////////////////////////////////////////////////// // Run --- main simulation control // void Run() { dprintf(("\n\t ********** Run() --- START \n")); // first some checks if( SIMLIB_Phase != INITIALIZATION ) SIMLIB_error(RunUseError); // bad use of Run() if( NextTime < StartTime ) SIMLIB_internal_error(); // never reached ###??? // welcome to the SIMLIB simulation control algorithm :-) // initialize variables SIMLIB_Phase = SIMULATION; StopFlag = false; // flag for stop simulation SIMLIB_StepCount = 0; // ### number of continuous steps // call init functions SIMLIB_ContinueInit(); // initialize status 2 ### CALL_HOOK(ZDelayTimerInit); // activate all ZDelayTimers CALL_HOOK(SamplerAct); // activate all Samplers CALL_HOOK(Break); // user can stop simulation by any key? #ifdef PN_SUPPORT // CPN extension CALL_HOOK(PN1); CALL_HOOK(PN2); #endif // main loop while( Time < EndTime && !StopFlag ) { int endFlag = NextTime > EndTime; // !!! ### achtung !!! if( endFlag ) _SetTime( NextTime, EndTime ); // limit NextTime to EndTime if( NextTime > Time ) { // no event at Time if( IntegratorContainer::isAny() || StatusContainer::isAny() ) { // there are integrators or status variables, so we enter // -------------- CONTINUOUS SIMULATION --------------- SIMLIB_ResetStatus = true; // don't use previous step buffers // is really needed always ???? CALL_HOOK(Delay); // DELAY: sample input while( NextTime > Time ) { // 'mini' steps // is not scheduled event or end ... IntegrationMethod::StepSim(); // *** continuous sim. step *** SIMLIB_StepCount++; // some statistics ###??? SIMLIB_DoConditions(); // perform state events CALL_HOOK(Delay); // DELAY: sample input CALL_HOOK(Break); // user can stop simulation by any key? if(StopFlag) // ### is possible !!! break; } } else { // no integrators, status blocks, ... _SetTime( Time, NextTime ); // set next event reactivation time # ifdef PN_SUPPORT // CPN extension CALL_HOOK(PN2); # endif } } // if (NextTime>Time) //CONDITION: is event in Time OR end of simulation if( endFlag ) break; // end of simulation ???### (pozor na podminky=>planovani!) if( StopFlag ) break; // ###??? must be here ??? while( Time >= NextTime && !SQS::Empty() ) { // there are events at Time SIMLIB_Current = SQS::Current(); // get first record from calendar SIMLIB_DoActions(); // perform actions (see waitunti.cc) SIMLIB_Current = NULL; // ###clear current activity pointer # ifdef PN_SUPPORT // CPN extension //###!!! move after loop !!! ??? why here? ask Vladimir! if( SQS::Empty() || Time < NextTime ) CALL_HOOK(PN1); # endif CALL_HOOK(Break); // user can stop simulation by any key? if( StopFlag ) break; } } // main loop IntegrationMethod::IntegrationDone(); // terminate integration run SIMLIB_Phase = TERMINATION; dprintf(("\n\t ********** Run() --- END \n")); } // end of module