org.matsim.contrib.drt.analysis.DynModeTripsAnalyser.java Source code

Java tutorial

Introduction

Here is the source code for org.matsim.contrib.drt.analysis.DynModeTripsAnalyser.java

Source

/* *********************************************************************** *
 * project: org.matsim.*
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 * copyright       : (C) 2017 by the members listed in the COPYING,        *
 *                   LICENSE and WARRANTY file.                            *
 * email           : info at matsim dot org                                *
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *   See also COPYING, LICENSE and WARRANTY file                           *
 *                                                                         *
 * *********************************************************************** */

/**
 * 
 */
package org.matsim.contrib.drt.analysis;

import java.awt.BasicStroke;
import java.awt.Color;
import java.io.BufferedWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYSeries;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.dvrp.data.Fleet;
import org.matsim.contrib.util.chart.ChartSaveUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.core.utils.misc.Time;
import org.matsim.vehicles.Vehicle;

/**
 * @author jbischoff
 *
 */

public class DynModeTripsAnalyser {

    public static Map<Double, List<DynModeTrip>> splitTripsIntoBins(Collection<DynModeTrip> trips, int startTime,
            int endTime, int binSize_s) {
        LinkedList<DynModeTrip> alltrips = new LinkedList<>();
        alltrips.addAll(trips);
        Collections.sort(alltrips);
        DynModeTrip currentTrip = alltrips.pollFirst();
        if (currentTrip.getDepartureTime() > endTime) {
            Logger.getLogger(DynModeTripsAnalyser.class).error("wrong end / start Times for analysis");
        }
        Map<Double, List<DynModeTrip>> splitTrips = new TreeMap<>();
        for (int time = startTime; time < endTime; time = time + binSize_s) {
            List<DynModeTrip> currentList = new ArrayList<>();
            splitTrips.put(Double.valueOf(time), currentList);
            while (currentTrip.getDepartureTime() < time + binSize_s) {
                currentList.add(currentTrip);
                currentTrip = alltrips.pollFirst();
                if (currentTrip == null) {
                    return splitTrips;
                }
            }

        }

        return splitTrips;

    }

    public static String summarizeTrips(List<DynModeTrip> trips, String delimiter) {
        DescriptiveStatistics waitStats = new DescriptiveStatistics();
        DescriptiveStatistics rideStats = new DescriptiveStatistics();
        DescriptiveStatistics distanceStats = new DescriptiveStatistics();
        DescriptiveStatistics directDistanceStats = new DescriptiveStatistics();

        DescriptiveStatistics traveltimes = new DescriptiveStatistics();

        DecimalFormat format = new DecimalFormat();
        format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
        format.setMinimumIntegerDigits(1);
        format.setMaximumFractionDigits(2);
        format.setGroupingUsed(false);

        for (DynModeTrip trip : trips) {
            if (trip.getToLinkId() == null) {
                continue;
            }
            waitStats.addValue(trip.getWaitTime());
            rideStats.addValue(trip.getInVehicleTravelTime());
            distanceStats.addValue(trip.getTravelDistance());
            directDistanceStats.addValue(trip.getUnsharedDistanceEstimate_m());
            traveltimes.addValue(trip.getInVehicleTravelTime() + trip.getWaitTime());
        }
        String value = format.format(waitStats.getValues().length) + delimiter + format.format(waitStats.getMean())
                + delimiter + format.format(waitStats.getMax()) + delimiter
                + format.format(waitStats.getPercentile(95)) + delimiter
                + format.format(waitStats.getPercentile(75)) + delimiter
                + format.format(waitStats.getPercentile(50)) + delimiter + format.format(rideStats.getMean())
                + delimiter + format.format(distanceStats.getMean()) + delimiter
                + format.format(directDistanceStats.getMean()) + delimiter + format.format(traveltimes.getMean());
        return value;
    }

    public static double getDirectDistanceMean(List<DynModeTrip> trips) {

        DescriptiveStatistics directDistanceStats = new DescriptiveStatistics();

        for (DynModeTrip trip : trips) {
            if (trip.getToLinkId() == null) {
                continue;
            }

            directDistanceStats.addValue(trip.getUnsharedDistanceEstimate_m());
        }
        return directDistanceStats.getMean();
    }

    public static void analyseDetours(Network network, List<DynModeTrip> trips, DrtConfigGroup drtCfg,
            String fileName) {
        if (trips == null)
            return;

        List<String> detours = new ArrayList<String>();
        XYSeries distances = new XYSeries("distances");
        XYSeries travelTimes = new XYSeries("travel times");
        XYSeries rideTimes = new XYSeries("ride times");

        for (DynModeTrip trip : trips) {
            if (trip.getToLinkId() == null) {
                continue; // unfinished trip (simulation stopped before arrival)
            }

            double travelTime = trip.getInVehicleTravelTime() + trip.getWaitTime();
            distances.add(trip.getTravelDistance(), trip.getUnsharedDistanceEstimate_m());
            travelTimes.add(travelTime, trip.getUnsharedTimeEstimate_m());
            rideTimes.add(trip.getInVehicleTravelTime(), trip.getUnsharedTimeEstimate_m());

            double distanceDetour = trip.getTravelDistance() / trip.getUnsharedDistanceEstimate_m();
            double timeDetour = travelTime / trip.getUnsharedTimeEstimate_m();
            detours.add(trip.getPerson() + ";" + trip.getTravelDistance() + ";"
                    + trip.getUnsharedDistanceEstimate_m() + ";" + distanceDetour + ";" + travelTime + ";"
                    + trip.getUnsharedTimeEstimate_m() + ";" + timeDetour);
        }

        collection2Text(detours, fileName + ".csv",
                "person;distance;unsharedDistance;distanceDetour;time;unsharedTime;timeDetour");

        final JFreeChart chart = DensityScatterPlots.createPlot("Travelled Distances", "travelled distance [m]",
                "unshared ride distance [m]", distances);
        ChartSaveUtils.saveAsPNG(chart, fileName + "_distancePlot", 1500, 1500);

        final JFreeChart chart2 = DensityScatterPlots.createPlot("Travel Times", "travel time [s]",
                "unshared ride time [s]", travelTimes,
                Pair.of(drtCfg.getMaxTravelTimeAlpha(), drtCfg.getMaxTravelTimeBeta()));
        ChartSaveUtils.saveAsPNG(chart2, fileName + "_travelTimePlot", 1500, 1500);

        final JFreeChart chart3 = DensityScatterPlots.createPlot("Ride Times", "ride time [s]",
                "unshared ride time [s]", rideTimes,
                Pair.of(drtCfg.getMaxTravelTimeAlpha(), drtCfg.getMaxTravelTimeBeta()));
        ChartSaveUtils.saveAsPNG(chart3, fileName + "_rideTimePlot", 1500, 1500);
    }

    public static void analyseWaitTimes(String fileName, List<DynModeTrip> trips, int binsize_s) {
        Collections.sort(trips);
        if (trips.size() == 0)
            return;
        int startTime = ((int) (trips.get(0).getDepartureTime() / binsize_s)) * binsize_s;
        int endTime = ((int) (trips.get(trips.size() - 1).getDepartureTime() / binsize_s) + binsize_s) * binsize_s;
        Map<Double, List<DynModeTrip>> splitTrips = splitTripsIntoBins(trips, startTime, endTime, binsize_s);

        DecimalFormat format = new DecimalFormat();
        format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
        format.setMinimumIntegerDigits(1);
        format.setMaximumFractionDigits(2);
        format.setGroupingUsed(false);

        SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");

        BufferedWriter bw = IOUtils.getBufferedWriter(fileName + ".csv");
        TimeSeriesCollection dataset = new TimeSeriesCollection();
        TimeSeriesCollection datasetrequ = new TimeSeriesCollection();
        TimeSeries averageWaitC = new TimeSeries("average");
        TimeSeries medianWait = new TimeSeries("median");
        TimeSeries p_5Wait = new TimeSeries("5th percentile");
        TimeSeries p_95Wait = new TimeSeries("95th percentile");
        TimeSeries requests = new TimeSeries("Ride requests");

        try {
            bw.write("timebin;trips;average_wait;min;p_5;p_25;median;p_75;p_95;max");
            for (Entry<Double, List<DynModeTrip>> e : splitTrips.entrySet()) {
                long rides = 0;
                double averageWait = 0;
                double min = 0;
                double p_5 = 0;
                double p_25 = 0;
                double median = 0;
                double p_75 = 0;
                double p_95 = 0;
                double max = 0;
                if (!e.getValue().isEmpty()) {
                    DescriptiveStatistics stats = new DescriptiveStatistics();
                    for (DynModeTrip t : e.getValue()) {
                        stats.addValue(t.getWaitTime());
                    }
                    rides = stats.getN();
                    averageWait = stats.getMean();
                    min = stats.getMin();
                    p_5 = stats.getPercentile(5);
                    p_25 = stats.getPercentile(25);
                    median = stats.getPercentile(50);
                    p_75 = stats.getPercentile(75);
                    p_95 = stats.getPercentile(95);
                    max = stats.getMax();

                }
                Minute h = new Minute(sdf2.parse(Time.writeTime(e.getKey())));

                medianWait.addOrUpdate(h, Double.valueOf(median));
                averageWaitC.addOrUpdate(h, Double.valueOf(averageWait));
                p_5Wait.addOrUpdate(h, Double.valueOf(p_5));
                p_95Wait.addOrUpdate(h, Double.valueOf(p_95));
                requests.addOrUpdate(h, rides * 3600. / binsize_s);// normalised [req/h]
                bw.newLine();
                bw.write(Time.writeTime(e.getKey()) + ";" + rides + ";" + format.format(averageWait) + ";"
                        + format.format(min) + ";" + format.format(p_5) + ";" + format.format(p_25) + ";"
                        + format.format(median) + ";" + format.format(p_75) + ";" + format.format(p_95) + ";"
                        + format.format(max));

            }
            bw.flush();
            bw.close();
            dataset.addSeries(averageWaitC);
            dataset.addSeries(medianWait);
            dataset.addSeries(p_5Wait);
            dataset.addSeries(p_95Wait);
            datasetrequ.addSeries(requests);
            JFreeChart chart = chartProfile(splitTrips.size(), dataset, "Waiting times", "Wait time (s)");
            JFreeChart chart2 = chartProfile(splitTrips.size(), datasetrequ, "Ride requests per hour",
                    "Requests per hour (req/h)");
            ChartSaveUtils.saveAsPNG(chart, fileName, 1500, 1000);
            ChartSaveUtils.saveAsPNG(chart2, fileName + "_requests", 1500, 1000);

        } catch (IOException | ParseException e) {

            e.printStackTrace();
        }

    }

    private static JFreeChart chartProfile(int length, TimeSeriesCollection dataset, String descriptor,
            String yax) {
        JFreeChart chart = ChartFactory.createTimeSeriesChart(descriptor, "Time", yax, dataset);

        // ChartFactory.createXYLineChart("TimeProfile", "Time", "Wait Time
        // [s]", dataset,
        // PlotOrientation.VERTICAL, true, false, false);

        XYPlot plot = chart.getXYPlot();
        plot.setRangeGridlinesVisible(false);
        plot.setDomainGridlinesVisible(false);
        plot.setBackgroundPaint(Color.white);

        NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
        yAxis.setAutoRange(true);

        XYItemRenderer renderer = plot.getRenderer();
        for (int s = 0; s < length; s++) {
            renderer.setSeriesStroke(s, new BasicStroke(2));
        }

        return chart;
    }

    public static <T> void collection2Text(Collection<T> c, String filename, String header) {
        BufferedWriter bw = IOUtils.getBufferedWriter(filename);
        try {
            if (header != null) {
                bw.write(header);
                bw.newLine();
            }
            for (Iterator<T> iterator = c.iterator(); iterator.hasNext();) {

                bw.write(iterator.next().toString());
                bw.newLine();
            }
            bw.flush();
            bw.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param vehicleDistances
     * @param iterationFilename
     */
    public static void writeVehicleDistances(Map<Id<Vehicle>, double[]> vehicleDistances,
            String iterationFilename) {
        String header = "vehicleId;drivenDistance_m;occupiedDistance_m;emptyDistance_m;revenueDistance_pm";
        BufferedWriter bw = IOUtils.getBufferedWriter(iterationFilename);
        DecimalFormat format = new DecimalFormat();
        format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
        format.setMinimumIntegerDigits(1);
        format.setMaximumFractionDigits(2);
        format.setGroupingUsed(false);
        try {
            bw.write(header);
            for (Entry<Id<Vehicle>, double[]> e : vehicleDistances.entrySet()) {
                double drivenDistance = e.getValue()[0];
                double revenueDistance = e.getValue()[1];
                double occDistance = e.getValue()[2];
                double emptyDistance = drivenDistance - occDistance;
                bw.newLine();
                bw.write(e.getKey().toString() + ";" + format.format(drivenDistance) + ";"
                        + format.format(occDistance) + ";" + format.format(emptyDistance) + ";"
                        + format.format(revenueDistance));
            }
            bw.flush();
            bw.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * @param vehicleDistances
     * @param string
     * @return
     */
    public static String summarizeVehicles(Map<Id<Vehicle>, double[]> vehicleDistances, String del) {
        DecimalFormat format = new DecimalFormat();
        format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
        format.setMinimumIntegerDigits(1);
        format.setMaximumFractionDigits(2);
        format.setGroupingUsed(false);

        DescriptiveStatistics driven = new DescriptiveStatistics();
        DescriptiveStatistics revenue = new DescriptiveStatistics();
        DescriptiveStatistics occupied = new DescriptiveStatistics();
        DescriptiveStatistics empty = new DescriptiveStatistics();

        for (double[] dist : vehicleDistances.values()) {
            driven.addValue(dist[0]);
            revenue.addValue(dist[1]);
            occupied.addValue(dist[2]);
            double emptyD = dist[0] - dist[2];
            empty.addValue(emptyD);
        }
        double d_r_d_t = revenue.getSum() / driven.getSum();
        // bw.write("iteration;vehicles;totalDistance;totalEmptyDistance;emptyRatio;totalRevenueDistance;averageDrivenDistance;averageEmptyDistance;averageRevenueDistance");
        String result = vehicleDistances.size() + del + format.format(driven.getSum()) + del
                + format.format(empty.getSum()) + del + format.format(empty.getSum() / driven.getSum()) + del
                + format.format(revenue.getSum()) + del + format.format(driven.getMean()) + del
                + format.format(empty.getMean()) + del + format.format(revenue.getMean()) + del
                + format.format(d_r_d_t);
        return result;
    }

    public static double getTotalDistance(Map<Id<Vehicle>, double[]> vehicleDistances) {
        DescriptiveStatistics driven = new DescriptiveStatistics();
        for (double[] dist : vehicleDistances.values()) {
            driven.addValue(dist[0]);
        }
        return driven.getSum();
    }

    /**
     * @param fleet
     * @return
     */
    public static int findMaxCap(Fleet fleet) {
        int maxCap = 0;
        for (org.matsim.contrib.dvrp.data.Vehicle v : fleet.getVehicles().values()) {
            if (v.getCapacity() > maxCap) {
                maxCap = (int) v.getCapacity();
            }
        }
        return maxCap;
    }

    public static String summarizeDetailedOccupancyStats(Map<Id<Vehicle>, double[]> vehicleDistances, String del,
            int maxcap) {
        DecimalFormat format = new DecimalFormat();
        format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
        format.setMinimumIntegerDigits(1);
        format.setMaximumFractionDigits(2);
        format.setGroupingUsed(false);

        double[] sum = new double[maxcap + 1];

        for (double[] dist : vehicleDistances.values()) {
            double emptyD = dist[0] - dist[2];
            sum[0] += emptyD;
            for (int i = 3; i < maxcap + 3; i++) {
                sum[i - 2] += dist[i];
            }
        }
        String result = "";
        for (int i = 0; i <= maxcap; i++) {
            result = result + ";" + format.format(sum[i]);
        }

        return result;
    }
}