IBM ILOG Dispatcher User's Manual > Transportation Industry Solutions > Docking Bays: Modeling External Resources > Model

Once you have written a description of this problem, you can use Dispatcher and Scheduler classes to model it.

Step 2   -  

Open the example file

Open the example file YourDispatcherHome/examples/src/tutorial/bays_partial.cpp in your development environment.

This lesson requires the IBM ILOG Scheduler library to model the resource and the pickup activity.

Step 3   -  

Include the Scheduler library

Add the following code after the comment //Include the Scheduler library.

#include <ilsched/iloscheduler.h>

As in the previous examples, you will use a RoutingModel class to call the functions that create the dimensions, nodes, vehicles, and visits. In this example, RoutingModel includes some Scheduler code and a function to create the docking bays.

Step 4   -  

Declare the RoutingModel class

Add the following code after the comment //Declare the RoutingModel class.

class RoutingModel {
  IloEnv              _env;
  IloModel            _mdl;
  IloDiscreteResource _bays;
  IloInt              _schedGranularity;

  void createDepotDockingBays(char* baysFileName);
  void createDimensions();
  void createNodes(char* nodeFileName);
  void createVehicles(char* vehicleFileName);
  void createVisits(char* visitsFileName);
public:
  RoutingModel(IloEnv env,
               int argc,
               char* argv[],
               IloInt schedGranularity = 100);
  ~RoutingModel() {}
  IloDiscreteResource getBays() const { return _bays; }
  IloEnv getEnv() const { return _env; }
  IloModel getModel() const { return _mdl; }
};

The docking bays are modeled in Scheduler as an instance of IloDiscreteResource. A discrete resource has a capacity that can vary over time, but is always available only as a positive integer.

The integer variable _schedGranularity is used as a scaling factor to relate floating-point dimension variables of Dispatcher to the integer values of the Scheduler resource time variables.

The function createDepotDockingBays creates the docking bays and their associated breaks.

Step 5   -  

Create the docking bays

Add the following code after the comment //Create the docking bays.

void RoutingModel::createDepotDockingBays(char* baysFileName) {
  // Scheduler environment settings
  IloCsvReader csvBaysReader(_env, baysFileName);
  IloCsvReader::LineIterator it(csvBaysReader);
  while (it.ok()) {
    IloCsvLine line = *it;
    IloSchedulerEnv schedEnv(_env);
    IloInt horizon = line.getIntByHeader("horizon");
    IloInt nbOfBays = line.getIntByHeader("bays");
    IloInt breakStart = line.getIntByHeader("breakStart");
    IloInt breakEnd = line.getIntByHeader("breakEnd");

    schedEnv.setHorizon(horizon * _schedGranularity);
    _bays = IloDiscreteResource(_env, nbOfBays);
    _bays.addBreak(breakStart * _schedGranularity,
                   breakEnd * _schedGranularity);
    ++it;
  }
  csvBaysReader.end();
}

Data for the discrete resource is read in from a csv file. The horizon is used to set the ending point of the time window over which the resource capacity constraints are enforced. The horizon is multiplied by a granularity (_schedGranularity) of 100 and then applied to an instance of IloSchedulerEnv (schedEnv). IloSchedulerEnv serves as the repository of all the default parameters used in creating Scheduler modeling objects.

The code _bays = IloDiscreteResource(_env, nbOfBays); creates the docking bays as a discrete resource of capacity nbOfBays (in this example, "3").

The break start and end times are also multiplied by _schedGranularity and then added to the _bays resource.

Here is an example to demonstrate the effect of the granularity: assume that v is a visit initially starting after 1.56 and ending before 3.34, with a duration of 1. If _schedGranularity == 1, then v will start after 2 and end before 3.34, and the resource will be required between 2 and 3. If _schedGranularity == 100, then v will start after 1.56 and end before 3.34, and the resource will be required at least between 156 and 256.

The dimensions, nodes, and vehicles are created just as for the PDP. The visits require additional code to model the docking bay pickups.

Step 6   -  

Create the docking bay pickups

    IloNumVar process(_env, 0, pickupMaxTime * _schedGranularity, ILOINT);
    IloActivity vehicleLoad(_env, process);
    IloNumVar start(_env, 0,  pickupMaxTime * _schedGranularity, ILOINT);
    IloNumVar end(_env, 0, pickupMaxTime * _schedGranularity, ILOINT);
    _mdl.add(start == vehicleLoad.getStartExpr());
    _mdl.add(end == vehicleLoad.getEndExpr());
    vehicleLoad.setName(pickupVisitName);
    vehicleLoad.setBreakable();
    _mdl.add(vehicleLoad.requires(_bays, 1));
    _mdl.add(start == pickup.getCumulVar(time) * _schedGranularity);
    _mdl.add(end <= (pickup.getCumulVar(time) + pickup.getDelayVar(time))
             * _schedGranularity);
    _mdl.add(process >= pickupTime * _schedGranularity);

Add the following code after the comment //Create the docking bay pickups.

This section of the function CreateVisits models the pickup and loading activity at the docking bay as a Scheduler activity vehicleLoad. The Scheduler member function IloActivity::setBreakable allows vehicleLoad to be interrupted by the personnel break. The member function IloActivity::requires is a resource constraint that states that the activity vehicleLoad requires (or consumes) exactly one of the resource _bays. For discrete resources, the activity requires the stated resource capacity at all times after the activity's start time (for the entire time the activity is occurring).

The activity vehicleLoad is constructed with a start time of start, an end time of end, and a processing time (total time the activity occurs) of process. Note that start, end and process are constructed from the floating point cumul and delay variables, which are then scaled by the granularity.

This section of code links the Dispatcher pickup visits to the Scheduler activities. It is important to have the visit cover the entire time of the activity; in other words, both start at the same time and the visits end after the activity end time (cumulVar + delayVar).

The processing time is constrained to be greater than or equal to the actual time to perform the pickup (it can be more than that due to breaks). The delay variable of the pickup is greater than or equal to the pickupTime to take into account the fact that the visit covers the activity, which itself can be interrupted by a break.