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