001/* *********************************************************************** * 002 * project: org.matsim.* 003 * * 004 * *********************************************************************** * 005 * * 006 * copyright : (C) 2015 by the members listed in the COPYING, * 007 * LICENSE and WARRANTY file. * 008 * email : info at matsim dot org * 009 * * 010 * *********************************************************************** * 011 * * 012 * This program is free software; you can redistribute it and/or modify * 013 * it under the terms of the GNU General Public License as published by * 014 * the Free Software Foundation; either version 2 of the License, or * 015 * (at your option) any later version. * 016 * See also COPYING, LICENSE and WARRANTY file * 017 * * 018 * *********************************************************************** */ 019 020package org.matsim.contrib.decongestion.handler; 021 022import java.util.HashMap; 023import java.util.Map; 024 025import org.apache.log4j.Logger; 026import org.matsim.api.core.v01.Id; 027import org.matsim.api.core.v01.Scenario; 028import org.matsim.api.core.v01.events.LinkEnterEvent; 029import org.matsim.api.core.v01.events.LinkLeaveEvent; 030import org.matsim.api.core.v01.events.PersonArrivalEvent; 031import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler; 032import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler; 033import org.matsim.api.core.v01.events.handler.PersonArrivalEventHandler; 034import org.matsim.contrib.decongestion.data.DecongestionInfo; 035import org.matsim.core.gbl.Gbl; 036import org.matsim.vehicles.Vehicle; 037 038import com.google.inject.Inject; 039 040/** 041 * 042 * Computes the total delay and travel time. 043 * 044 * WARNING: Link-based analysis. Ignores the travel time and delay on the first link of each trip, i.e. the link on which the trip has started. 045 * 046 * @author ikaddoura 047 */ 048 049public class DelayAnalysis implements LinkEnterEventHandler, LinkLeaveEventHandler, PersonArrivalEventHandler { 050 private static final Logger log = Logger.getLogger(DelayAnalysis.class); 051 052 private Map<Id<Vehicle>, Double> vehicleId2enterTime = new HashMap<>(); 053 054 @Inject 055 private Scenario scenario; 056 057 @Inject(optional = true) 058 private DecongestionInfo decongestionInfo; 059 060 // some aggregated numbers for analysis purposes 061 private double totalDelayPerDay_sec = 0.; 062 private double totalTravelTimePerDay_sec = 0.; 063 private int warnCnt = 0; 064 private int warnCnt2 = 0; 065 066 public void setScenario(Scenario scenario) { 067 this.scenario = scenario; 068 } 069 070 @Override 071 public void reset(int iteration) { 072 this.totalDelayPerDay_sec = 0.; 073 this.totalTravelTimePerDay_sec = 0.; 074 this.vehicleId2enterTime.clear(); 075 } 076 077 @Override 078 public void handleEvent(LinkLeaveEvent event) { 079 080 if (this.vehicleId2enterTime.get(event.getVehicleId()) != null) { 081 082 // compute the travel time 083 double traveltimeThisAgent = event.getTime() - this.vehicleId2enterTime.get(event.getVehicleId()); 084 double freespeedTravelTime = 1 + Math.ceil(this.scenario.getNetwork().getLinks().get(event.getLinkId()).getLength() / this.scenario.getNetwork().getLinks().get(event.getLinkId()).getFreespeed()); 085 double delayThisAgent = traveltimeThisAgent - freespeedTravelTime; 086 087 if (delayThisAgent < -1.) { 088 if (warnCnt2 <= 5) { 089 log.warn("The delay is negative! Delay:" + delayThisAgent + " | traveltime: " + traveltimeThisAgent + " | freespeed traveltime: " + freespeedTravelTime + " | link: " + event.getLinkId() ); 090 log.warn(event.toString()); 091 if (warnCnt2 == 5) { 092 log.warn( Gbl.FUTURE_SUPPRESSED ) ; 093 } 094 warnCnt2++; 095 } 096 } else if (delayThisAgent < 0.) { 097 if (warnCnt == 0) { 098 warnCnt ++; 099 log.info("Delay is " + delayThisAgent + ". A negative delay of down to -1 sec may result from rounding errors. Therefore it is ignored and set to " + 100 "zero."); 101 log.info( Gbl.ONLYONCE ) ; 102 } 103 delayThisAgent = 0.; 104 105 } else if (delayThisAgent > 0.) { 106 this.totalDelayPerDay_sec = this.totalDelayPerDay_sec + delayThisAgent; 107 } 108 109 this.totalTravelTimePerDay_sec = this.totalTravelTimePerDay_sec + traveltimeThisAgent; 110 } 111 } 112 113 @Override 114 public void handleEvent(LinkEnterEvent event) { 115 if (this.decongestionInfo == null || !this.decongestionInfo.getTransitVehicleIDs().contains(event.getVehicleId())) { 116 this.vehicleId2enterTime.put(event.getVehicleId(), event.getTime()); 117 } 118 } 119 120 @Override 121 public void handleEvent(PersonArrivalEvent event) { 122 this.vehicleId2enterTime.remove(event.getPersonId()); 123 } 124 125 public double getTotalDelay() { 126 return totalDelayPerDay_sec; 127 } 128 129 public double getTotalTravelTime() { 130 return totalTravelTimePerDay_sec; 131 } 132 133} 134