/////////////////////////////////////////////////////////////////////////////
// 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
syntax highlighted by Code2HTML, v. 0.9.1