Introduction to Simulation
In order to use the simulator, we must first write a simulation scenario. A scenario is a parallel and/or sequential composition of stochastic processes, which is a finite random sequence of events. We invoke a stochastic process with a specified distribution of inter-arrival times. In other words, stochastic processes define series of events that occur in simulation.
Stochastic Processes and Operations
The following snippet of code creates a single stochastic process that will generate 1000 events of type SimpleEvent
with an interarrival time of 2000ms (or 2s) of simulation time.
- Java
-
static Operation<SimpleEvent> simpleEventGen1 = new Operation<SimpleEvent>() { @Override public SimpleEvent generate() { return new SimpleEvent(); } }; StochasticProcess p1 = new StochasticProcess() { { eventInterarrivalTime(constant(2000)); raise(1000, simpleEventGen1); } };
- Scala
-
val simpleEventGen1 = Op { (_: Unit) => SimpleEvent() }; /* ... */ raise(1000, simpleEventGen1).arrival(constant(2.seconds))
However, in the example above, all events are exactly the same; there is no variation to the 1000 events generated. We can generate events that differ slightly, by having the event take an integer parameter and generating this parameter randomly.
- Java
-
static Operation1<SimpleEvent, Long> simpleEventGen2 = new Operation1<SimpleEvent, Long>() { @Override public SimpleEvent generate(Long param) { return new SimpleEvent(param); } }; StochasticProcess p2 = new StochasticProcess() { { eventInterarrivalTime(constant(2000)); raise(1000, simpleEventGen2, uniform(1000L, 2000L)); } };
- Scala
-
val simpleEventGen2 = Op { (param: java.lang.Long) => SimpleEvent(param) }; /* ... */ raise(1000, simpleEventGen2, uniform(1000L, 2000L)).arrival(constant(2.seconds))
The new events generated have a parameter that takes uniform long random values between 1000 and 2000. Both the interarrival time and the event parameters are defined as instances of Distribution
, and the constant
constant
and uniform
uniform
are just helper methods to generate these distributions.
There are several types of operations (Operation
, Operation1
, …, Operation5
) that can be interpreted by the simulator, and they differ in the number of parameters they take to customise the generated events. All parameters are given as distributions. There are a number of distributions provided by the simulator, or you can write your own distribution by extending Distribution
.
In order to start the stochastic processes and to define the iterative/parallel behaviour, the StochasticProcess
has a number of start/terminate methodsa builder DSL
is provided.
If we want to start the two stochastic processes above, a possible example would be:
- Java
-
p1.start(); p2.startAfterTerminationOf(1000, p1); terminateAfterTerminationOf(1000, p2);
- Scala
-
val scenario = raise(1000, simpleEventGen1) .arrival(constant(2.seconds)) .andThen(1.second) .afterTermination( raise(1000, simpleEventGen2, uniform(1000L, 2000L)) .arrival(constant(2.seconds)) ) .andThen(2.seconds) .afterTermination(Terminate);
The above example would start the first stochastic process at the beginning of the simulation. After all 1000 if its events are generated, the simulation waits another 1000ms of simulation time and then starts the second stochastic process. After generating all 1000 of its defined events and waiting another 2000ms of simulation time, the simulation is terminated.
Simluation Scenario
The stochastic processes created and their order will be defined within a SimulationScenario
, such as the on the in the following classobject.
Basic Scenario
- Java
-
package jexamples.simulation.basic; import se.sics.kompics.simulator.adaptor.Operation; import se.sics.kompics.simulator.adaptor.Operation1; import se.sics.kompics.simulator.SimulationScenario; public class BasicSimulation { static Operation<SimpleEvent> simpleEventGen1 = new Operation<SimpleEvent>() { @Override public SimpleEvent generate() { return new SimpleEvent(); } }; static Operation1<SimpleEvent, Long> simpleEventGen2 = new Operation1<SimpleEvent, Long>() { @Override public SimpleEvent generate(Long param) { return new SimpleEvent(param); } }; public static SimulationScenario scenario() { SimulationScenario scen = new SimulationScenario() { { StochasticProcess p1 = new StochasticProcess() { { eventInterarrivalTime(constant(2000)); raise(1000, simpleEventGen1); } }; StochasticProcess p2 = new StochasticProcess() { { eventInterarrivalTime(constant(2000)); raise(1000, simpleEventGen2, uniform(1000L, 2000L)); } }; p1.start(); p2.startAfterTerminationOf(1000, p1); terminateAfterTerminationOf(1000, p2); } }; return scen; } }
- Scala
-
package sexamples.simulation.basic import se.sics.kompics.sl._ import se.sics.kompics.sl.simulator._ import se.sics.kompics.simulator.{SimulationScenario => JSimulationScenario} import scala.concurrent.duration._ case class SimpleEvent(num: Long = 0L) extends KompicsEvent; object BasicSimulation { import Distributions._ // needed for the distributions, but needs to be initialised after setting the seed implicit val random = JSimulationScenario.getRandom(); val simpleEventGen1 = Op { (_: Unit) => SimpleEvent() }; val simpleEventGen2 = Op { (param: java.lang.Long) => SimpleEvent(param) }; val _ignoreThisIsJustForDocs = { /* ... */ raise(1000, simpleEventGen1).arrival(constant(2.seconds)) /* ... */ raise(1000, simpleEventGen2, uniform(1000L, 2000L)).arrival(constant(2.seconds)) () } val scenario = raise(1000, simpleEventGen1) .arrival(constant(2.seconds)) .andThen(1.second) .afterTermination( raise(1000, simpleEventGen2, uniform(1000L, 2000L)) .arrival(constant(2.seconds)) ) .andThen(2.seconds) .afterTermination(Terminate); }
Running a Simulation Scenario
In order to run the simulation scenario, the following Main
code is required:
- Java
-
package jexamples.simulation.basic; import se.sics.kompics.simulator.SimulationScenario; import se.sics.kompics.simulator.run.LauncherComp; public class Main { public static void main(String[] args) { long seed = 123; SimulationScenario.setSeed(seed); SimulationScenario simpleBootScenario = BasicSimulation.scenario(); simpleBootScenario.simulate(LauncherComp.class); } }
- Scala
-
package sexamples.simulation.basic import se.sics.kompics.simulator.SimulationScenario import se.sics.kompics.simulator.run.LauncherComp object Main { def main(args: Array[String]): Unit = { val seed = 123; SimulationScenario.setSeed(seed); val simpleBootScenario = BasicSimulation.scenario; simpleBootScenario.simulate(classOf[LauncherComp]); } }
In the above code, we set the simulation scenario seed (more about this seed in later sections), we construct the simulation scenario and we use the LauncherComp
to execute it.
We can attempt to run this using:
runMain jexamples.simulation.basic.Main
runMain sexamples.simulation.basic.Main
However, the execution will fail with an exception indicating that we are triggering an invalid event. In fact, the only events that can be generated by stochastic processes and interpreted by the simulator are:
You can read more about operations, distributions and stochastic processes in the section on Scenarios.