001/* *********************************************************************** * 002 * project: org.matsim.* 003 * CalcLegTimes.java 004 * * 005 * *********************************************************************** * 006 * * 007 * copyright : (C) 2007 by the members listed in the COPYING, * 008 * LICENSE and WARRANTY file. * 009 * email : info at matsim dot org * 010 * * 011 * *********************************************************************** * 012 * * 013 * This program is free software; you can redistribute it and/or modify * 014 * it under the terms of the GNU General Public License as published by * 015 * the Free Software Foundation; either version 2 of the License, or * 016 * (at your option) any later version. * 017 * See also COPYING, LICENSE and WARRANTY file * 018 * * 019 * *********************************************************************** */ 020 021package org.matsim.analysis; 022 023import org.apache.log4j.Logger; 024import org.matsim.api.core.v01.IdMap; 025import org.matsim.api.core.v01.events.ActivityEndEvent; 026import org.matsim.api.core.v01.events.ActivityStartEvent; 027import org.matsim.api.core.v01.events.PersonArrivalEvent; 028import org.matsim.api.core.v01.events.PersonDepartureEvent; 029import org.matsim.api.core.v01.events.handler.ActivityEndEventHandler; 030import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; 031import org.matsim.api.core.v01.events.handler.PersonArrivalEventHandler; 032import org.matsim.api.core.v01.events.handler.PersonDepartureEventHandler; 033import org.matsim.api.core.v01.population.Person; 034import org.matsim.core.api.experimental.events.EventsManager; 035import org.matsim.core.utils.io.IOUtils; 036import org.matsim.core.utils.io.UncheckedIOException; 037import org.matsim.core.utils.misc.Time; 038 039import javax.inject.Inject; 040import java.io.BufferedWriter; 041import java.io.IOException; 042import java.util.Map; 043import java.util.TreeMap; 044 045/** 046 * @author mrieser 047 * 048 * Calculates the distribution of legs-durations, e.g. how many legs took at 049 * most 5 minutes, how many between 5 and 10 minutes, and so on. 050 * Also calculates the average trip duration. 051 * Trips ended because of vehicles being stuck are not counted. 052 */ 053public class CalcLegTimes implements PersonDepartureEventHandler, PersonArrivalEventHandler, 054 ActivityEndEventHandler, ActivityStartEventHandler { 055 056 private final static Logger log = Logger.getLogger(CalcLegTimes.class); 057 058 private static final int SLOT_SIZE = 300; // 5-min slots 059 private static final int MAXINDEX = 12; // slots 0..11 are regular slots, slot 12 is anything above 060 061 private final IdMap<Person, Double> agentDepartures = new IdMap<>(Person.class); 062 private final IdMap<Person, Double> agentArrivals = new IdMap<>(Person.class); 063 private final Map<String, int[]> legStats = new TreeMap<>(); 064 private final IdMap<Person, String> previousActivityTypes = new IdMap<>(Person.class); 065 private double sumTripDurations = 0; 066 private int sumTrips = 0; 067 068 @Inject 069 CalcLegTimes(EventsManager eventsManager) { 070 eventsManager.addHandler(this); 071 } 072 073 public CalcLegTimes() { 074 075 } 076 077 @Override 078 public void handleEvent(ActivityEndEvent event) { 079 this.previousActivityTypes.put(event.getPersonId(), event.getActType()); 080 } 081 082 @Override 083 public void handleEvent(final PersonDepartureEvent event) { 084 this.agentDepartures.put(event.getPersonId(), event.getTime()); 085 } 086 087 @Override 088 public void handleEvent(final PersonArrivalEvent event) { 089 this.agentArrivals.put(event.getPersonId(), event.getTime()); 090 } 091 092 093 @Override 094 public void handleEvent(ActivityStartEvent event) { 095 Double depTime = this.agentDepartures.remove(event.getPersonId()); 096 Double arrTime = this.agentArrivals.remove(event.getPersonId()); 097 if (depTime != null) { 098 double travTime = arrTime - depTime; 099 String fromActType = previousActivityTypes.remove(event.getPersonId()); 100 String toActType = event.getActType(); 101 String legType = fromActType + "---" + toActType; 102 int[] stats = this.legStats.get(legType); 103 if (stats == null) { 104 stats = new int[MAXINDEX+1]; 105 for (int i = 0; i <= MAXINDEX; i++) { 106 stats[i] = 0; 107 } 108 this.legStats.put(legType, stats); 109 } 110 stats[getTimeslotIndex(travTime)]++; 111 112 this.sumTripDurations += travTime; 113 this.sumTrips++; 114 } 115 } 116 117 118 @Override 119 public void reset(final int iteration) { 120 this.previousActivityTypes.clear(); 121 this.agentDepartures.clear(); 122 this.legStats.clear(); 123 this.sumTripDurations = 0; 124 this.sumTrips = 0; 125 } 126 127 public Map<String, int[]> getLegStats() { 128 return this.legStats; 129 } 130 131 public static int getTimeslotIndex(final double time_s) { 132 int idx = (int)(time_s / SLOT_SIZE); 133 if (idx > MAXINDEX) idx = MAXINDEX; 134 return idx; 135 } 136 137 public double getAverageTripDuration() { 138 return (this.sumTripDurations / this.sumTrips); 139 } 140 141 public void writeStats(final String filename) { 142 try (BufferedWriter legStatsFile = IOUtils.getBufferedWriter(filename)) { 143 writeStats(legStatsFile); 144 } catch (IOException e) { 145 log.error(e); 146 } 147 } 148 149 public void writeStats(final java.io.Writer out) throws UncheckedIOException { 150 try { 151 boolean first = true; 152 for (Map.Entry<String, int[]> entry : this.legStats.entrySet()) { 153 String key = entry.getKey(); 154 int[] counts = entry.getValue(); 155 if (first) { 156 first = false; 157 out.write("pattern"); 158 for (int i = 0; i < counts.length; i++) { 159 out.write("\t" + (i*SLOT_SIZE/60) + "+"); 160 } 161 out.write("\n"); 162 } 163 out.write(key); 164 for (int count : counts) { 165 out.write("\t" + count); 166 } 167 out.write("\n"); 168 } 169 out.write("\n"); 170 if (this.sumTrips == 0) { 171 out.write("average trip duration: no trips!"); 172 } else { 173 out.write("average trip duration: " 174 + (this.sumTripDurations / this.sumTrips) + " seconds = " 175 + Time.writeTime(((int)(this.sumTripDurations / this.sumTrips)))); 176 } 177 out.write("\n"); 178 } catch (IOException e) { 179 throw new UncheckedIOException(e); 180 } finally { 181 try { 182 out.flush(); 183 } catch (IOException e) { 184 log.error(e); 185 } 186 } 187 } 188}