All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rinde.sim.pdptw.common.StatsTracker Maven / Gradle / Ivy

The newest version!
/**
 * 
 */
package rinde.sim.pdptw.common;

import static com.google.common.collect.Maps.newLinkedHashMap;
import static rinde.sim.core.Simulator.SimulatorEventType.STARTED;
import static rinde.sim.core.Simulator.SimulatorEventType.STOPPED;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.END_DELIVERY;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.END_PICKUP;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.NEW_PARCEL;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.NEW_VEHICLE;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.START_DELIVERY;
import static rinde.sim.core.model.pdp.PDPModel.PDPModelEventType.START_PICKUP;
import static rinde.sim.core.model.pdp.PDPScenarioEvent.ADD_DEPOT;
import static rinde.sim.core.model.pdp.PDPScenarioEvent.ADD_PARCEL;
import static rinde.sim.core.model.pdp.PDPScenarioEvent.ADD_VEHICLE;
import static rinde.sim.core.model.pdp.PDPScenarioEvent.TIME_OUT;
import static rinde.sim.core.model.road.AbstractRoadModel.RoadEventType.MOVE;
import static rinde.sim.scenario.ScenarioController.EventType.SCENARIO_FINISHED;
import static rinde.sim.scenario.ScenarioController.EventType.SCENARIO_STARTED;

import java.util.Map;

import rinde.sim.core.Simulator;
import rinde.sim.core.Simulator.SimulatorEventType;
import rinde.sim.core.graph.Point;
import rinde.sim.core.model.pdp.PDPModel;
import rinde.sim.core.model.pdp.PDPModel.PDPModelEventType;
import rinde.sim.core.model.pdp.PDPModelEvent;
import rinde.sim.core.model.pdp.Parcel;
import rinde.sim.core.model.pdp.Vehicle;
import rinde.sim.core.model.road.AbstractRoadModel.RoadEventType;
import rinde.sim.core.model.road.MoveEvent;
import rinde.sim.core.model.road.MovingRoadUser;
import rinde.sim.core.model.road.RoadModel;
import rinde.sim.event.Event;
import rinde.sim.event.EventAPI;
import rinde.sim.event.EventDispatcher;
import rinde.sim.event.Listener;
import rinde.sim.scenario.ScenarioController;
import rinde.sim.scenario.TimedEvent;

import com.google.common.base.Optional;

/**
 * @author Rinde van Lon 
 * 
 */
final class StatsTracker {

  final EventDispatcher eventDispatcher;
  final TheListener theListener;
  final Simulator simulator;
  final RoadModel roadModel;

  enum StatisticsEventType {
    PICKUP_TARDINESS, DELIVERY_TARDINESS, ALL_VEHICLES_AT_DEPOT;
  }

  StatsTracker(ScenarioController scenContr, Simulator sim) {
    eventDispatcher = new EventDispatcher(StatisticsEventType.values());
    theListener = new TheListener();
    simulator = sim;
    scenContr.getEventAPI().addListener(theListener, SCENARIO_STARTED,
        SCENARIO_FINISHED, ADD_DEPOT, ADD_PARCEL, ADD_VEHICLE, TIME_OUT);
    simulator.getEventAPI().addListener(theListener, STARTED, STOPPED);
    roadModel = Optional.fromNullable(
        simulator.getModelProvider().getModel(RoadModel.class)).get();
    roadModel.getEventAPI().addListener(theListener, MOVE);
    Optional
        .fromNullable(simulator.getModelProvider().getModel(PDPModel.class))
        .get()
        .getEventAPI()
        .addListener(theListener, START_PICKUP, END_PICKUP, START_DELIVERY,
            END_DELIVERY, NEW_PARCEL, NEW_VEHICLE);
  }

  EventAPI getEventAPI() {
    return eventDispatcher.getPublicEventAPI();
  }

  /**
   * @return A {@link StatisticsDTO} with the current simulation stats.
   */
  public StatisticsDTO getStatsDTO() {
    final int vehicleBack = theListener.lastArrivalTimeAtDepot.size();
    long overTime = 0;
    if (theListener.simFinish) {
      for (final Long time : theListener.lastArrivalTimeAtDepot.values()) {
        if (time - theListener.scenarioEndTime > 0) {
          overTime += time - theListener.scenarioEndTime;
        }
      }
    }

    long compTime = theListener.computationTime;
    if (compTime == 0) {
      compTime = System.currentTimeMillis() - theListener.startTimeReal;
    }

    return new StatisticsDTO(theListener.totalDistance,
        theListener.totalPickups, theListener.totalDeliveries,
        theListener.totalParcels, theListener.acceptedParcels,
        theListener.pickupTardiness, theListener.deliveryTardiness, compTime,
        simulator.getCurrentTime(), theListener.simFinish, vehicleBack,
        overTime, theListener.totalVehicles, theListener.distanceMap.size(),
        simulator.getTimeUnit(), roadModel.getDistanceUnit(),
        roadModel.getSpeedUnit());
  }

  class TheListener implements Listener {

    private static final double MOVE_THRESHOLD = 0.0001;
    // parcels
    protected int totalParcels;
    protected int acceptedParcels;

    // vehicles
    protected int totalVehicles;
    protected final Map distanceMap;
    protected double totalDistance;
    protected final Map lastArrivalTimeAtDepot;

    protected int totalPickups;
    protected int totalDeliveries;
    protected long pickupTardiness;
    protected long deliveryTardiness;

    // simulation
    protected long startTimeReal;
    protected long startTimeSim;
    protected long computationTime;
    protected long simulationTime;

    protected boolean simFinish;
    protected long scenarioEndTime;

    TheListener() {
      totalParcels = 0;
      acceptedParcels = 0;

      totalVehicles = 0;
      distanceMap = newLinkedHashMap();
      totalDistance = 0d;
      lastArrivalTimeAtDepot = newLinkedHashMap();

      totalPickups = 0;
      totalDeliveries = 0;
      pickupTardiness = 0;
      deliveryTardiness = 0;

      simFinish = false;
    }

    @Override
    public void handleEvent(Event e) {
      if (e.getEventType() == SimulatorEventType.STARTED) {
        startTimeReal = System.currentTimeMillis();
        startTimeSim = simulator.getCurrentTime();
        computationTime = 0;

      } else if (e.getEventType() == SimulatorEventType.STOPPED) {
        computationTime = System.currentTimeMillis() - startTimeReal;
        simulationTime = simulator.getCurrentTime() - startTimeSim;
      } else if (e.getEventType() == RoadEventType.MOVE) {
        final MoveEvent me = (MoveEvent) e;
        increment(me.roadUser, me.pathProgress.distance.getValue()
            .doubleValue());
        totalDistance += me.pathProgress.distance.getValue().doubleValue();
        // if we are closer than 10 cm to the depot, we say we are 'at'
        // the depot
        if (Point.distance(me.roadModel.getPosition(me.roadUser),
            ((DefaultVehicle) me.roadUser).dto.startPosition) < MOVE_THRESHOLD) {
          // only override time if the vehicle did actually move
          if (me.pathProgress.distance.getValue().doubleValue() > MOVE_THRESHOLD) {
            lastArrivalTimeAtDepot.put(me.roadUser, simulator.getCurrentTime());
            if (totalVehicles == lastArrivalTimeAtDepot.size()) {
              eventDispatcher.dispatchEvent(new Event(
                  StatisticsEventType.ALL_VEHICLES_AT_DEPOT, this));
            }
          }
        } else {
          lastArrivalTimeAtDepot.remove(me.roadUser);
        }

      } else if (e.getEventType() == PDPModelEventType.START_PICKUP) {
        final PDPModelEvent pme = (PDPModelEvent) e;
        final long latestBeginTime = pme.parcel.getPickupTimeWindow().end
            - pme.parcel.getPickupDuration();
        if (pme.time > latestBeginTime) {
          final long tardiness = pme.time - latestBeginTime;
          pickupTardiness += tardiness;
          eventDispatcher.dispatchEvent(new StatisticsEvent(
              StatisticsEventType.PICKUP_TARDINESS, this, pme.parcel,
              pme.vehicle, tardiness, pme.time));
        }
      } else if (e.getEventType() == PDPModelEventType.END_PICKUP) {
        totalPickups++;
      } else if (e.getEventType() == PDPModelEventType.START_DELIVERY) {
        final PDPModelEvent pme = (PDPModelEvent) e;
        final long latestBeginTime = pme.parcel.getDeliveryTimeWindow().end
            - pme.parcel.getDeliveryDuration();
        if (pme.time > latestBeginTime) {
          final long tardiness = pme.time - latestBeginTime;
          deliveryTardiness += tardiness;
          eventDispatcher.dispatchEvent(new StatisticsEvent(
              StatisticsEventType.DELIVERY_TARDINESS, this, pme.parcel,
              pme.vehicle, tardiness, pme.time));
        }
      } else if (e.getEventType() == PDPModelEventType.END_DELIVERY) {
        totalDeliveries++;
      } else if (e.getEventType() == ADD_PARCEL) {
        // scenario event
        totalParcels++;
      } else if (e.getEventType() == NEW_PARCEL) {
        // pdp model event
        acceptedParcels++;
      } else if (e.getEventType() == ADD_VEHICLE) {
        totalVehicles++;
      } else if (e.getEventType() == NEW_VEHICLE) {
        final PDPModelEvent ev = (PDPModelEvent) e;
        lastArrivalTimeAtDepot.put(ev.vehicle, simulator.getCurrentTime());
      } else if (e.getEventType() == TIME_OUT) {
        simFinish = true;
        scenarioEndTime = ((TimedEvent) e).time;
      } else {
        // System.out.println("fall through: " + e);
      }

    }

    protected void increment(MovingRoadUser mru, double num) {
      if (!distanceMap.containsKey(mru)) {
        distanceMap.put(mru, num);
      } else {
        distanceMap.put(mru, distanceMap.get(mru) + num);
      }
    }
  }

  static class StatisticsEvent extends Event {
    private static final long serialVersionUID = 3941445489579790997L;

    final Parcel parcel;
    final Vehicle vehicle;
    final long tardiness;
    final long time;

    StatisticsEvent(Enum type, Object pIssuer, Parcel p, Vehicle v,
        long tar, long tim) {
      super(type, pIssuer);
      parcel = p;
      vehicle = v;
      tardiness = tar;
      time = tim;
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy