Copyright © 2020 Gerd Wagner (CC BY-NC)
Published 2020-08-17
This tutorial article explains how to use the OESjs-Core0 library, which implements a minimal architecture for an Object Event simulator, supporting model variables, object types, event types, next-event time progression and simple simulation experiments.
Simulation is used widely today: in many scientific disciplines for investigating specific research questions, in engineering for testing the performance of designs, in education for providing interactive learning experiences, and in entertainment for making games.
Both static systems/structures and dynamic systems can be modeled and simulated. Modeling and simulation (M&S) of static structures, such as the surface textures of materials, is only an issue in physics and computer graphics, while M&S of dynamic systems is an issue in all scientific and engineering disciplines, including management science, economics and other social sciences.
A dynamic system may be subject to discrete or continuous state changes. For simulating a dynamic system one has to model
A (purely) continuous dynamic system does not include events and their causal effects (list items 2-4), but only objects that are subject to continuous state changes (list items 1 and 5). A (purely) discrete dynamic system does not include any continuous state changes of objects (list item 5). Many real-world systems include both discrete and continuous state changes, in which case they may be called hybrid dynamic systems.
In this tutorial, we are only concerned with discrete state changes. Consequently, we only consider purely discrete dynamic systems, also called discrete event systems, which consist of:
This means that for modeling such a system, we have to
Let's look at an example. We model a system of one or more service desks, each of them having its own queue, as a discrete event system:
The potentially relevant object types of the system under investigation are:
The potentially relevant event types are:
When making a simulation design based on the conceptual model of the system under investigation, wee need to abstract away from many items of the conceptual model for obtaining a sufficiently simple design. The right degree of abstraction depends on the purpose of the model. But abstracting away from too many things may make a model too unnatural and not sufficiently generic, implying that it cannot be easily extended to model additional features (such as more than one service desk).
In our example, the purpose of the simulation model is to compute the maximum queue length and possibly also the service utilization. So, we may abstract away from the following object types:
Notice that, for simplicity, we consider the customer that is currently being served to be part of the queue. In this way, in the simulation program, we can check if the service desk is busy by testing if the length of the queue is greater than 0. In fact, for being able to compute the service utilization and the maximum queue length, the queue length is the only relevant state variable.
State variables can be modeled in the simple form of global variables or in the form of attributes of suitable object types. Consequently, the simplest model we can make for the given problem, called Service-Desk-0, has only one global variable: queueLength. But, as an alternative, more explicit, model, called Service-Desk-1, we will also model the system state in terms of (one or more) ServiceDesk objects having only one property: queueLength. As opposed to the simpler model defining queueLength as a global variable, this model allows defining simulation scenarios with two or more service desks operating simultaneously.
We also look for opportunities to simplify our event model by dropping event types that are not needed, e.g., because their events temporally coincide with events of another type. This is the case with service terminations and customer departure events. Consequently, we can drop the event type service terminations.
There are two situations when a new service can be started: either when the waiting line is empty and a new customer arrives, or when the waiting line is not empty and a service terminates. Therefore, any service start event immediately follows either a customer arrival or a customer departure event, and we may abstract away from service start events and drop the corresponding event type from the design model.
So we only need to consider customer arrival and customer departure events, modeled with the two event types Arrival and Departure.
The event type Arrival is an example of a type of exogenous events, which are not caused by any causal regularity of the system under investigation and, therefore, have to be modeled with a recurrence function that allows to compute the time of the next occurrence of an event of that type. In OES, exogenous event types are a built-in concept such that an OES simulator takes care of creating the next exogenous event whenever an event of that type is processed. This mechanism makes sure that there is a continuous stream of exogenous events throughout a simulation run.
We also have to model the random variations of two variables: (1) the recurrence of (that is, the time in-between two) customer arrival events and (2) the service duration. In a class model, such random variables can be defined as special class-level ("static") operations, with a stereotype «rv», in the class to which they belong, as shown in the diagrams below.
We model the recurrence of customer arrival events as a discrete random variable with a uniform distribution between 1 and 6 minutes, which we express in the class diagram of the information design model by appending the symbolic expression U{1-6} within curly braces to the operation declaration, following the UML syntax for property/method modifiers.
We model the service time random variable with an empirical distribution of 2 minutes with probability 0.3, 3 minutes with probability 0.5 and 4 minutes with probability 0.2, using the symbolic expression Freq{ 2:0.3, 3:0.5, 4:0.2}.
Computationally, object types and event types correspond to classes, either of an object-oriented information model, such as a UML class diagram, or of a computer program written in an object-oriented programming language, such as Java or JavaScript.
As discussed above, the simplest model for the service desk problem with maximum queue length statistics (available in the Sim4edu library as Service-Desk-0) has only one global variable: queueLength, which is a non-negative integer, and a global function for computing the random service time, but no object type.
An information model for Service-Desk-0 consists of a special class for defining model variables and functions, and two classes for defining the event types Arrival and Departure, as shown in Figure 1-1. An information design model for Service-Desk-0.
In addition to an information design model for defining the simulation system's state structure, we also need to make a process design model for defining the dynamics of the simulation system. The dynamics of a system consists of events triggering state changes and follow-up events. A process model can be expressed with the help of event rules, which define what happens when an event (of a certain type) occurs, or, more specifically, which state changes and which follow-up events are caused by an event of that type.
Event rules can be expressed with the help of a process model diagram or in pseudo-code, or in a simulation or programming language. The following Event Graph provides a process design model for the Service-Desk-0 simulation scenario. Circles represent events (or, more precisely, event types) and arrows, which may be annotated with a delay expression, such as +serviceTime(), represent event scheduling relationships. An arrow with a mini-diamond at its source end represents a conditional event scheduling relationship where the condition is expressed in brackets below or above the arrow.
Event Graphs have originally been proposed by L. Schruben (1983). Their visual syntax has been improved and harmonized with the business process modeling language BPMN in the Discrete Event Process Modeling Notation (DPMN) proposed by Wagner (2018) and more thoroughly described in the book Discrete Event Simulation Engineering.
The following table shows the two event rules defined by the above Event Graph, expressed in pseudo-code.
ON (event type) | DO (event routine) |
Arrival @ t | INCREMENT queueLength IF queueLength = 1 THEN sTime := serviceTime() SCHEDULE Departure @ (t + sTime) |
Departure @ t | DECREMENT queueLength IF queueLength > 0 THEN sTime := serviceTime() SCHEDULE Departure @ (t + sTime) |
In our extended model (Service-Desk-1) we represent the state variable queueLength as an attribute of an object type ServiceDesk. This results in a model with three classes, the object class ServiceDesk with an attribute queueLength, and the event classes Arrival and Departure, both with a reference property serviceDesk for referencing the service desk at which an event occurs. When we also want to compute the service utilization statistics, we need to add an attribute serviceTime to the Departure class for being able to update the service utilization statistics when a customer departs.
Both event types, Arrival and Departure, now have a many-to-one association with the object type ServiceDesk. This expresses the fact that any such event occurs at a particular service desk, which participates in the event. This association is implemented in the form of a reference property serviceDesk in each of the two event types, as shown in Figure 1-3. An information design model for Service-Desk-1.
In addition to an information model, we need to make a process model, which captures the dynamics of the service desk system consisting of arrival and departure events triggering state changes and follow-up events. The following DPMN Process Diagram provides a process design model for the Service-Desk-1 simulation scenario. As in Event Graphs, circles represent event types and arrows represent event scheduling relationships. DPMN extends Event Graphs by adding object rectangles, attached to event circles, representing state change patterns for objects that are affected by events of that type.
The following table shows the two event rules defined by the DPMN diagram, which now account for the fact that both types of events occur at a particular service desk that is referenced by the event expression parameter sd.
ON (event type) | DO (event routine) |
Arrival( sd) @ t with sd : ServiceDesk | INCREMENT sd.queueLength IF sd.queueLength = 1 THEN sTime := ServiceDesk.serviceTime() SCHEDULE Departure( sTime, sd) @(t + sTime) |
Departure( sd) @ t with sd : ServiceDesk | DECREMENT sd.queueLength IF sd.queueLength > 0 THEN sTime := ServiceDesk.serviceTime() SCHEDULE Departure( sTime, sd) @(t + sTime) |
The JavaScript-based simulator OESjs-Core0 implements the Object Event Simulation (OES) paradigm, representing a general Discrete Event Simulation approach based on object-oriented modeling and event scheduling. In OES, a model normally defines various types of objects and events, but OESjs-Core0 also supports models without objects, if they define state variables in the form of global model variables, instead.
An OESjs-Core0 simulation consists of the OESjs-Core0 library code and the following files to be created by the simulation developer:
OESjs-Core0 supports two forms of simulations:
Standalone scenario simulations, which are good for getting a quick impression of a simulation model, e.g., by checking some simple statistics.
Simple simulation experiments, which are defined as a set of replicated simulation scenario runs, providing summary statistics like mean, standard deviation, minimum/maximum and confidence intervals for each statistics variable defined in the underlying model.
Using a simulation library like OESjs-Core0 means that only the model-specific logic has to be coded (in the form of object types, event types, event routines and other functions for model-specific computations), but not the general simulator operations (e.g., time progression and statistics) and the environment handling (e.g., user interfaces for statistics output).
The following sections present the basic concepts of the OESjs-Core0 simulation library, and show how to implement the service desk models described in Chapter 1. Introduction to Object Event Modeling.
While you can directly run a OESjs Core1 simulation model from a remote website (e.g., from the OES GitHub website), you can only run it from your local file system after changing your browser's default configuration. For FireFox, you have to set the configuration property
privacy.file_unique_origin
to false by enteringabout:config
in the browser's web address bar.
A simulation model has an underlying time model, which can be either discrete time, when setting
sim.model.time = "discrete";
or continuous time, when setting
sim.model.time = "continuous";
Choosing a discrete time model means that time is measured in steps (with equal durations), and all temporal random variables used in the model need to be discrete (i.e., based on discrete probability distributions). Choosing a continuous time model means that one has to define a simulation time granularity, as explained in the next sub-section.
In both cases, the underlying simulation time unit can be either left unspecified (e.g., in the case of an abstract time model), or it can be set to one of the time units "ms", "s", "min", "hour", "day", "week", "month" or "year", as in
sim.model.timeUnit = "hour";
Typical examples of time models are:
An abstract discrete model of time where time runs in steps without any concrete meaning:
sim.model.time = "discrete";
A concrete discrete model of time in number of days:
sim.model.time = "discrete"; sim.model.timeUnit = "day";
A concrete continuous model of time in number of seconds:
sim.model.time = "continuous"; sim.model.timeUnit = "s";
A model's time granularity is the time delay until the next moment, such that the model does not allow considering an earlier next moment. This is captured by the simulation parameter nextMomentDeltaT used by the simulator for scheduling immediate events with a minimal delay. When a simulation model is based on discrete time, nextMomentDeltaT is set to 1, referring to the next time point. When a simulation model is based on continuous time, nextMomentDeltaT is set to the default value 0.001, unless the model parameter sim.model.nextMomentDeltaT
is explicitly assigned in the simulation.js file.
An important issue in simulation is the question how the simulation time is advanced by the simulator. The OES paradigm supports next-event time progression and fixed-increment time progression, as well as their combination.
An OESjs-Core0 model with fixed-increment time progression has to define a suitable periodic time event type, like EachSecond
or EachDay
in the form of an exogenous event type with a recurrence function returning the value 1. Such a model can be used for
Examples of discrete event simulation models with fixed-increment time progression and no explicit events are the Schelling Segregation Model and the Susceptible-Infected-Recovered (SIR) Disease Model.
In the simple model of a service desk discussed in the previous section, we define one (global) model variable, queueLength, one model function, serviceTime(), and two event types, as shown in the following class diagram:
Notice that this model does not define any object type, which implies that the system state is not composed of the states of objects, but of the states of model variables (here the state of the model variable queueLength). The discrete random variable for modeling the random variation of service durations is implemented as a model function serviceTime
shown in the Global Variables and Functions class. It samples integers between 2 and 4 from the empirical probability distribution Frequency{ 2:0.3, 3:0.5, 4:0.2}. The model can be coded with OESjs-Core0 in the following way:
// (global) model variable sim.model.v.queueLength = 0; // (global) model function sim.model.f.serviceTime = function () { var r = math.getUniformRandomInteger( 0, 99); if ( r < 30) return 2; // probability 0.30 else if ( r < 80) return 3; // probability 0.50 else return 4; // probability 0.20 };
You can run this Service-Desk-0 model from the project's GitHub website. An example of a run of this model is shown in the following simulation log:
Step | Time | System State | Future Events |
---|---|---|---|
0 | 0 | queueLength: 0 | CustomerArrival@1 |
1 | 1 | queueLength: 1 | CustomerDeparture@4, CustomerArrival@4 |
2 | 4 | queueLength: 1 | CustomerDeparture@6, CustomerArrival@7 |
3 | 6 | queueLength: 0 | CustomerArrival@7 |
4 | 7 | queueLength: 1 | CustomerDeparture@11, CustomerArrival@13 |
5 | 11 | queueLength: 0 | CustomerArrival@13 |
6 | 13 | queueLength: 1 | CustomerDeparture@15, CustomerArrival@19 |
7 | 15 | queueLength: 0 | CustomerArrival@19 |
... | ... | ... | ... |
49 | 114 | queueLength: 0 | CustomerArrival@117 |
50 | 117 | queueLength: 1 | CustomerArrival@118, CustomerDeparture@119 |
51 | 118 | queueLength: 2 | CustomerDeparture@119, CustomerArrival@119 |
52 | 119 | queueLength: 2 | CustomerArrival@121, CustomerDeparture@123 |
53 | 121 | queueLength: 3 | CustomerDeparture@123, CustomerArrival@124 |
54 | 123 | queueLength: 2 | CustomerArrival@124, CustomerDeparture@126 |
55 | 124 | queueLength: 3 | CustomerArrival@125, CustomerDeparture@126 |
56 | 125 | queueLength: 4 | CustomerDeparture@126, CustomerArrival@128 |
57 | 126 | queueLength: 3 | CustomerArrival@128, CustomerDeparture@128 |
58 | 128 | queueLength: 3 | CustomerArrival@129, CustomerDeparture@131 |
59 | 129 | queueLength: 4 | CustomerDeparture@131, CustomerArrival@133 |
60 | 131 | queueLength: 3 | CustomerArrival@133, CustomerDeparture@135 |
61 | 133 | queueLength: 4 | CustomerDeparture@135, CustomerArrival@137 |
62 | 135 | queueLength: 3 | CustomerArrival@137, CustomerDeparture@137 |
63 | 137 | queueLength: 3 | CustomerArrival@139, CustomerDeparture@141 |
64 | 139 | queueLength: 4 | CustomerDeparture@141, CustomerArrival@142 |
65 | 141 | queueLength: 3 | CustomerArrival@142, CustomerDeparture@144 |
66 | 142 | queueLength: 4 | CustomerDeparture@144, CustomerArrival@147 |
67 | 144 | queueLength: 3 | CustomerArrival@147, CustomerDeparture@148 |
68 | 147 | queueLength: 4 | CustomerDeparture@148, CustomerArrival@148 |
69 | 148 | queueLength: 4 | CustomerArrival@149, CustomerDeparture@151 |
70 | 149 | queueLength: 5 | CustomerDeparture@151, CustomerArrival@151 |
... | ... | ... | ... |
Object types are defined in the form of classes. Consider the object type ServiceDesk defined in the following Service-Desk-1 model:
While queueLength
was defined as a global variable in the Service-Desk-0 model, it is now defined as an attribute of the object type ServiceDesk:
class ServiceDesk extends oBJECT { constructor({ id, name, queueLength}) { super( id, name); this.queueLength = queueLength; } static serviceTime() { var r = math.getUniformRandomInteger( 0, 99); if ( r < 30) return 2; // probability 0.3 else if ( r < 80) return 3; // probability 0.5 else return 4; // probability 0.2 } } ServiceDesk.labels = {"queueLength":"qLen"}; // for the log
Notice that, in OESjs, object types are defined as subtypes of the pre-defined class oBJECT
, from which they inherit an integer-valued id
attribute and an optional name
attribute. When a property has a label
(defined by the class-level (map-valued) property labels
), it is shown in the simulation log.
You can run this simulation model from the project's GitHub website.
In OES, there is a distinction between two kinds of events:
Here is an example of an exogenous event type definition in OESjs-Core0:
class CustomerArrival extends eVENT { constructor({ occTime, serviceDesk}) { super( occTime); this.serviceDesk = serviceDesk; } onEvent() { ... } ... }
The definition of the CustomerArrival event type includes a reference property serviceDesk, which is used for referencing the service desk object at which a customer arrival event occurs. In OESjs, event types are defined as subtypes of the pre-defined class eVENT
, from which they inherit an attribute occTime
, which holds the occurrence time of an event. As opposed to objects, events do normally not have an ID, nor a name.
Each event type needs to define an onEvent
method that implements the event rule for events of the defined type. Event rules are discussed below.
Exogenous events occur periodically. They are therefore defined with a recurrence function, which provides the time in-between two events (often in the form of a random variable). The recurrence function is defined as a class-level ("static") method:
class CustomerArrival extends eVENT { ... static recurrence() { return math.getUniformRandomInteger( 1, 6); } }
Notice that the recurrence function of CustomerArrival is coded with the library method math.getUniformRandomInteger
, which allows sampling from discrete uniform probability distribution functions.
In the case of an exogenous event type definition, a createNextEvent method has to be defined for assigning event properties and returning the next event of that type, which is scheduled by invoking the recurrence function for setting its ocurrenceTime and by copying all participant references (such as the serviceDesk reference).
class CustomerArrival extends eVENT { ... createNextEvent() { return new CustomerArrival({ occTime: this.occTime + CustomerArrival.recurrence(), serviceDesk: this.serviceDesk }); } static recurrence() {...} }
The second event type of the Service-Desk-1 model, Departure, is an example of a type of caused events:
class CustomerDeparture extends eVENT { constructor({ occTime, serviceDesk}) { super( occTime); this.serviceDesk = serviceDesk; } onEvent() { ... } }
A caused event type does neither define a recurrence function nor a createNextEvent method.
An event rule for an event type defines what happens when an event of that type occurs, by specifying the caused state changes and follow-up events. In OESjs, event rules are coded as onEvent
methods of the class that implements the event type. These methods return a set of events (more precisely, a set of JS objects representing events).
Notice that in the DES literature, event rule methods are called event routines.
For instance, in the CustomerArrival
class, the following event rule method is defined:
class CustomerArrival extends eVENT { ... onEvent() { var followupEvents=[]; // increment queue length due to newly arrived customer this.serviceDesk.queueLength++; // update statistics sim.stat.arrivedCustomers++; if (this.serviceDesk.queueLength > sim.stat.maxQueueLength) { sim.stat.maxQueueLength = this.serviceDesk.queueLength; } // if the service desk is not busy if (this.serviceDesk.queueLength === 1) { followupEvents.push( new CustomerDeparture({ occTime: this.occTime + ServiceDesk.serviceTime(), serviceDesk: this.serviceDesk })); } return followupEvents; } }
The context of this event rule method is the event that triggers the rule, that is, the variable this
references a JS object that represents the triggering event. Thus, the expression this.serviceDesk
refers to the service desk object associated with the current customer arrival event, and the statement this.serviceDesk.queueLength++
increments the queueLength attribute of this service desk object (as an immediate state change).
The following event rule method is defined in the CustomerDeparture
class.
class CustomerDeparture extends eVENT { ... onEvent() { var followupEvents=[]; // decrement queue length due to departure this.serviceDesk.queueLength--; // update statistics sim.stat.departedCustomers++; // if there are still customers waiting if (this.serviceDesk.queueLength > 0) { // start next service and schedule its end/departure followupEvents.push( new CustomerDeparture({ occTime: this.occTime + ServiceDesk.serviceTime(), serviceDesk: this.serviceDesk })); } return followupEvents; } }
Random variables are implemented as functions that sample from specific probability distribution functions (PDFs). Simulation frameworks typically provide a library of predefined parametrized PDF sampling methods, which can be bound to a (possibly seeded) stream of pseudo-random numbers.
The OESjs-Core0 simulator does not support seeding and provides only two predefined parametrized PDF sampling functions:
Probability Distribution Function | OES-Core-0 Library Method | Example |
Uniform | getUniformRandomNumber ( lowerBound, upperBound) | math.getUniformRandomNumber( 0.5, 1.5) |
Discrete Uniform | getUniformRandomInteger ( lowerBound, upperBound) | math.getUniformRandomInteger( 1, 6) |
For obtaining a complete executable simulation scenario, a simulation model has to be complemented with simulation parameter settings and an initial system state.
In general, we may have more than one simulation scenario for a simulation model. For instance, the same model could be used in two different scenarios with different initial states. However, only from OES Core 1 upwards, multiple scenarios per model will be supported.
A simulation scenario consists of
durationInSimTime
, andAn empty template for the simulation.js file has the following structure:
// ***** Simulation Model ******************* sim.model.time = "..."; // discrete or continuous sim.model.timeIncrement = ...; // optional sim.model.timeUnit = "..."; // optional (ms|s|min|hour|day|week|month|year) sim.model.v.aModelVariable = ...; // (developer-defined) model variables sim.model.f.aModelFunction = ...; // (developer-defined) model functions sim.model.objectTypes = [...]; // (developer-defined) object types sim.model.eventTypes = [...]; // (developer-defined) event types // ***** Simulation Parameters ************** sim.scenario.durationInSimTime = ...; // ***** Initial State ********************** sim.scenario.setupInitialState = function () { // Initialize model variables ... // Create initial objects ... // Schedule initial events ... }; // ***** Ex-Post Statistics ***************** sim.model.statistics = {...};
We briefly discuss each group of scenario information items in the following sub-sections.
In OESjs-Core0, the only simulation parameter is durationInSimTime, which defines the duration of a simulation run in terms of simulation time. By default, when this attribute is not set, the simulation runs forever.
Defining an initial state means:
A setupInitialState
procedure takes care of these initial state definitions. A global model variable is initialized in the following way:
sim.scenario.setupInitialState = function () { // Initialize model variables sim.model.v.queueLength = 0; // Create initial objects ... // Schedule initial events ... };
An initial state object is created by instantiating an object type of the simulation model with suitable initial property values, as shown in the following example:
sim.scenario.setupInitialState = function () { // Initialize model variables ... // Create initial objects let serviceDesk1 = new ServiceDesk({id: 1, queueLength: 0}); // Schedule initial events ... };
Notice that object IDs are positive integers, but when used as keys in the map sim.objects
, they are converted to strings.
Instead of assigning a fixed value to a property like queueLength
for defining an object's initial state, as in queueLength: 0
, we can also assign it a fixed expression, as in queueLength: Math.round(12/30)
.
An initial event is scheduled by adding it to the Future Events List (FEL), as shown in the following example:
sim.scenario.setupInitialState = function () { // Initialize model variables ... // Create initial objects let desk1 = new ServiceDesk({id: 1, queueLength: 0}); // Schedule initial events sim.FEL.add( new CustomerArrival({occTime:1, serviceDesk: desk1})); };
Initial objects or events can be parametrized with the help of model parameters.
In scientific and engineering simulation projects the main goal is getting estimates of the values of certain variables or performance indicators with the help of statistical methods. In educational simulations, statistics can be used for observing simulation runs and for learning the dynamics of a simulation model.
For collecting statistics, suitable statistics variables have to be defined, as in the following example:
sim.model.setupStatistics = function () { sim.stat.arrivedCustomers = 0; sim.stat.departedCustomers = 0; sim.stat.maxQueueLength = 0; };
Statistics variables have to be updated in onEvent methods. For instance, the variables arrivedCustomers and maxQueueLength are updated in the onEvent method of the CustomerArrival event class:
class CustomerArrival extends eVENT { ... onEvent() { ... // update statistics sim.stat.arrivedCustomers++; if (this.serviceDesk.queueLength > sim.stat.maxQueueLength) { sim.stat.maxQueueLength = this.serviceDesk.queueLength; } ... } }
In certain cases, a statistics variable can only be computed at the end of a simulation run. For this purpose, there is the option to define a computeFinalStatistics procedure:
sim.model.computeFinalStatistics = function () { // percentage of business days without stock-outs sim.stat.serviceLevel = (sim.time - sim.stat.nmrOfStockOuts) / sim.time * 100; };
After running a simulation scenario, the statistics results are shown in a table:
arrivedCustomers | 289 |
departedCustomers | 288 |
maxQueueLength | 4 |
There are different types of simulation experiments. In the simplest case, a simulation scenario is run repeatedly for being able to compute aggregate statistics.
An experiment type is defined for a given simulation model and an experiment of that type is run on top of a given simulation scenario for that model.
A simple experiment type is defined with a sim.experimentType
record on top of a model by defining (1) the number of replications and (2) possibly a list of seed values, one for each replication. The following code shows an example of a simple experiment type definition:
1 2 3 4 | sim.experimentType = { title: "Simple Experiment with 10 replications, each running for 1000 time units (days)", nmrOfReplications: 10 }; |
Running this simple experiment means running the underlying scenario 10 times. The resulting statistics are composed of the statistics for each replication complemented with summary statistics listing averages, standard deviations, min/max values and confidence intervals, as shown in the following table:
Experiment Results | |||
---|---|---|---|
Replication | Statistics | ||
arrivedCustomers | departedCustomers | maxQueueLength | |
1 | 285 | 283 | 7 |
2 | 274 | 274 | 6 |
3 | 285 | 285 | 4 |
4 | 287 | 286 | 5 |
5 | 284 | 284 | 6 |
6 | 300 | 299 | 4 |
7 | 288 | 286 | 5 |
8 | 286 | 284 | 4 |
9 | 286 | 285 | 4 |
10 | 295 | 293 | 6 |
Average | 287 | 285.9 | 5.1 |
Std.dev. | 6.848 | 6.506 | 1.101 |
Minimum | 274 | 274 | 4 |
Maximum | 300 | 299 | 7 |
CI Lower | 282.9 | 281.9 | 4.4 |
CI Upper | 291 | 289.6 | 5.7 |
The OESjs-Core0 simulator can generate a simulation log, which allows to inspect the evolving states of a simulation run. Inspecting the simulation log can help to understand the dynamics of a model, or it can be used for finding logical flaws in it.
The contents of the simulation log can be controlled by defining labels for those object properties that are to be displayed in the log. For instance, in the case of the Service-Desk-1 model, a label "qLen" is defined for the queueLength
property of ServiceDesk objects by setting
ServiceDesk.labels = {"queueLength":"qLen"};
This results in the following simulation log:
Step | Time | System State | Future Events |
---|---|---|---|
0 | 0 | ServiceDesk-1{ qLen: 0} | CustomerArrival@1 |
1 | 1 | ServiceDesk-1{ qLen: 1} | CustomerDeparture@5, CustomerArrival@6 |
2 | 5 | ServiceDesk-1{ qLen: 0} | CustomerArrival@6 |
3 | 6 | ServiceDesk-1{ qLen: 1} | CustomerArrival@7, CustomerDeparture@10 |
4 | 7 | ServiceDesk-1{ qLen: 2} | CustomerDeparture@10, CustomerArrival@10 |
5 | 10 | ServiceDesk-1{ qLen: 2} | CustomerArrival@12, CustomerDeparture@13 |
6 | 12 | ServiceDesk-1{ qLen: 3} | CustomerDeparture@13, CustomerArrival@16 |
7 | 13 | ServiceDesk-1{ qLen: 2} | CustomerArrival@16, CustomerDeparture@16 |
8 | 16 | ServiceDesk-1{ qLen: 2} | CustomerDeparture@19, CustomerArrival@21 |
9 | 19 | ServiceDesk-1{ qLen: 1} | CustomerArrival@21, CustomerDeparture@23 |
OES Core 0 is the minimal architecture for an OE simulator, supporting
recurrence
and nextEvent
functionsThe OES Core 0 simulator's information architecture is described by the following class diagram, which defines the names of classes, properties and methods/functions:
The Run-Standalone-Scenario procedure is described by the following activity diagram: