Processes Step by Step

Model Implementation (2)

The Dynamic Model Components

   
 

After finishing the model class we have to implement the dynamic model components of our model. Using the process-oriented modelling style, dynamic model components are represented as simulation processes. In our model, we have identified the trucks, the van carriers and the truck generator to be dynamic model components (also called active entities). For each type of active entity we will derive a class from desmoj.core.simulator.SimProcess and specify its behaviour in the lifeCycle() method.

Let's start with the easiest one, the truck generator. It just loops continually through (i) generating a new truck, (ii) activating that truck, and (iii) determining the next arrival time and schedule itself for reactivation for this point in time. Refer to the conceptual model if you need to look up the details of its life cycle again.

First of all, derive a class named TruckGenerator from SimProcess. Don't forget to import the desmoj.core.simulator package. Add the constructor, which is equally straightforward as the one in our model class as it only passes all parameters to the constructor of the superclass.

import desmoj.core.simulator.*;
import co.paralleluniverse.fibers.SuspendExecution;
/**
 * This class represents a process source, which continually generates
 * trucks in order to keep the simulation running.
 *
 * It will create a new truck, activate it (so that it arrives at
 * the terminal) and then wait until the next truck arrival is
 * due.
 */
public class TruckGenerator extends SimProcess {

   /**
    * TruckGenerator constructor comment.
    * @param owner the model this truck generator belongs to
    * @param name this truck generator's name
    * @param showInTrace flag to indicate if this process shall produce output
    *                    for the trace
    */
   public TruckGenerator(Model owner, String name, boolean showInTrace) {
      super(owner, name, showInTrace);
   }

   ...

} /* end of process class */

Now all left to do is actually define what the truck generator does, i.e. implement its lifeCycle() method.

   /**
    * describes this process's life cycle: continually generate new trucks.
    */
   public void lifeCycle() throws SuspendExecution {

      // get a reference to the model
      ProcessesExample model = (ProcessesExample)getModel();

      // endless loop:
      while (true) {

         // create a new truck
         // Parameters:
         // model       = it's part of this model
         // "Truck"     = name of the object
         // true        = yes please, show the truck in trace file
         Truck truck = new Truck(model, "Truck", true);

         // now let the newly created truck roll on the parking-lot
         // which means we will activate it after this truck generator
         truck.activateAfter(this);

         // wait until next truck arrival is due
         hold(new TimeSpan(model.getTruckArrivalTime(), TimeUnit.MINUTES));
         // from inside to outside...
         // we draw a new inter-arrival time
         // we make a TimeSpan object out of it and
         // we wait for exactly this period of time
      }
   }

The activities performed inside the endless while() loop are:

  1. Instantiate a new truck object by calling the constructor of our own Truck class (we will implement this later).
  2. Schedule an activation note for the truck process by calling its activateAfter() method and passing it a reference to this truck generator. This ensures that the new truck will be activated at the current point in simulation time, right after the truck generator passes control back to the scheduler.

    Note: Alternatively, we could have used the following statement:

    truck.activate(new TimeSpan(0), TimeUnit.MINUTES));

    This also schedules an activation note for the truck process at the current point in simulation time. The only difference is that the truck process might not be activated directly after the truck generator passes control to the scheduler. If there are already other processes scheduled for activation at the same point in time, the activation note for the new truck process will be inserted behind these other activation notes. Using the activateAfter() method will result in inserting the truck's activation note at the top of the event list, before all other entries. You should be aware of these details as they can result in so-called simulation artifacts.

  3. Wait until the next truck will arrive. As we know when this will happen -- by drawing a sample from the random number stream modelling inter-arrival times -- we will use the hold() method of the SimProcess class to express waiting for a pre-defined duration. Calling hold() results in scheduling the truck generator for activation at the next truck's arrival time and then passing control over to the scheduler. This means the lifeCycle() of the truck generator will be interrupted and resumed right after the hold() statement when it is reactivated.

Observe that lifeCycle() method is declared to throw a SuspendExecution. This is required for the internal process scheduling logic, putting a "mark" where process execution can be interrupted.

One detail remains to be explained: What is the purpose of the first statement inside the lifeCycle() method? The answer is simple: It's there to provide us with a convenient reference to the model so that we can access its static model components. In this case, we need to draw a sample from the truck arrival time distribution by calling the getTruckArrival() method of our model. To be able to do so, we need a reference to the model object. DESMO-J provides the getModel() method as a member of the ModelComponent class for this aim. All subclasses of ModelComponent like SimProcess or Model inherit this method. The problem we run into when using the method is that it returns an object of type Model while we need an object of the more specialised type ProcessesExample. Thus we are forced to perform a type cast, resulting in rather awkward code. For example, the hold() statement in the above life cycle would look like this:

hold(new TimeSpan(((ProcessesExample)getModel()).getTruckArrivalTime(), TimeUnit.MINUTES));

This is rather cumbersome to type, especially if we have to access model components more than once during a life cycle, and doesn't make the code easy to read. So calling getModel() and performing the requested type cast once at the beginning of the lifeCycle() method provides for a good shortcut. Alternatively, you may add a field to the process class and assign it the associated model inside the constructor. We will use this approach in the two remaining classes.



   
  http://desmoj.sourceforge.net/tutorial/processes/impl20.html