playground.christoph.evacuation.analysis.AgentsInMunicipalityEventsHandler.java Source code

Java tutorial

Introduction

Here is the source code for playground.christoph.evacuation.analysis.AgentsInMunicipalityEventsHandler.java

Source

/* *********************************************************************** *
 * project: org.matsim.*
 * AgentsInMunicipalityEventsHandler.java
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 * copyright       : (C) 2012 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 playground.christoph.evacuation.analysis;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.zip.GZIPOutputStream;

import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.events.ActivityEndEvent;
import org.matsim.api.core.v01.events.ActivityStartEvent;
import org.matsim.api.core.v01.events.PersonStuckEvent;
import org.matsim.api.core.v01.events.Event;
import org.matsim.api.core.v01.events.LinkEnterEvent;
import org.matsim.api.core.v01.events.LinkLeaveEvent;
import org.matsim.api.core.v01.events.handler.ActivityEndEventHandler;
import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler;
import org.matsim.api.core.v01.events.handler.PersonStuckEventHandler;
import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler;
import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.gbl.Gbl;
import org.matsim.core.scenario.ScenarioImpl;
import org.matsim.facilities.ActivityFacility;
import org.matsim.facilities.Facility;
import org.matsim.households.Household;
import org.matsim.utils.objectattributes.ObjectAttributes;

import playground.christoph.evacuation.controler.EvacuationConstants;

import com.vividsolutions.jts.geom.Geometry;

public class AgentsInMunicipalityEventsHandler implements LinkEnterEventHandler, LinkLeaveEventHandler,
        ActivityStartEventHandler, ActivityEndEventHandler, PersonStuckEventHandler {

    final private static Logger log = Logger.getLogger(AgentsInMunicipalityEventsHandler.class);

    private final static int maxTime = 36 * 3600;
    private final static String separator = "\t";
    private final static String newLine = "\n";
    private final static Charset charset = Charset.forName("UTF-8");

    private final Scenario scenario;
    private final ObjectAttributes householdObjectAttributes;
    private final String outputFile;

    private final Set<Id> insideAgents;
    private final Set<Id> residentAgents;
    private final Set<Id> residentStuckInsideAgents;
    private final Set<Id> residentStuckOutsideAgents;
    private final Set<Id> otherStuckInsideAgents;
    private final Set<Id> otherStuckOutsideAgents;
    private final Set<Id> residentHouseholds;
    private final Map<Integer, List<Id>> residentHouseholdHHTPs;
    private final CoordAnalyzer coordAnalyzer;
    private final List<PlotData> plotData;

    private FileOutputStream fos;
    private GZIPOutputStream gzos;
    private OutputStreamWriter osw;
    private BufferedWriter bw;

    private int currentSecond = 0;

    public AgentsInMunicipalityEventsHandler(Scenario scenario, ObjectAttributes householdObjectAttributes,
            String outputFile, Geometry area) {
        this.scenario = scenario;
        this.householdObjectAttributes = householdObjectAttributes;
        this.outputFile = outputFile;

        insideAgents = new HashSet<Id>();
        residentAgents = new HashSet<Id>();
        residentStuckInsideAgents = new HashSet<Id>();
        residentStuckOutsideAgents = new HashSet<Id>();
        otherStuckInsideAgents = new HashSet<Id>();
        otherStuckOutsideAgents = new HashSet<Id>();
        residentHouseholds = new HashSet<Id>();
        residentHouseholdHHTPs = new TreeMap<Integer, List<Id>>();
        plotData = new ArrayList<PlotData>();

        coordAnalyzer = new CoordAnalyzer(area);

        getResidents();
    }

    private void getResidents() {
        for (Household household : ((ScenarioImpl) scenario).getHouseholds().getHouseholds().values()) {

            boolean isAffected = this.isHouseholdAffected(household);

            if (isAffected) {
                // mark household as resident household and add it to the HHTP map
                residentHouseholds.add(household.getId());
                int HHTP = Integer.valueOf(String.valueOf(householdObjectAttributes
                        .getAttribute(household.getId().toString(), EvacuationConstants.HOUSEHOLD_HHTP)));
                List<Id> list = residentHouseholdHHTPs.get(HHTP);
                if (list == null) {
                    list = new ArrayList<Id>();
                    residentHouseholdHHTPs.put(HHTP, list);
                }
                list.add(household.getId());

                // mark household members as residents and agents within the area
                for (Id id : household.getMemberIds()) {
                    insideAgents.add(id);
                    residentAgents.add(id);
                }
            }
        }
    }

    private boolean isHouseholdAffected(Household household) {

        for (Id id : household.getMemberIds()) {
            Person person = scenario.getPopulation().getPersons().get(id);

            if (person.getSelectedPlan().getPlanElements().size() == 0)
                continue;
            else {
                Activity activity = (Activity) person.getSelectedPlan().getPlanElements().get(0);

                if (activity.getFacilityId() != null) {
                    ActivityFacility facility = scenario.getActivityFacilities().getFacilities()
                            .get(activity.getFacilityId());
                    return this.coordAnalyzer.isFacilityAffected(facility);
                } else {
                    Link link = scenario.getNetwork().getLinks().get(activity.getLinkId());
                    log.warn("No facility defined in activity - taking coordinate from activity...");
                    return this.coordAnalyzer.isLinkAffected(link);
                }
            }
        }
        throw new RuntimeException("No Coordinate found for household " + household.getId());
    }

    public void beforeEventsReading() {
        try {
            fos = new FileOutputStream(outputFile + ".txt.gz");
            gzos = new GZIPOutputStream(fos);
            osw = new OutputStreamWriter(gzos, charset);
            bw = new BufferedWriter(osw);

            // write header
            bw.write("time");
            bw.write(separator);
            bw.write("total inside area");
            bw.write(separator);
            bw.write("residents inside area");
            bw.write(separator);
            bw.write("commuters inside area");
            bw.write(newLine);

            // write statistics before first event
            printStatistics();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void afterEventsReading() {
        try {
            // check consistency of counts
            checkConsistency();

            // write statistics after last event
            printStatistics();

            bw.close();
            osw.close();
            gzos.close();
            fos.close();

            writeGraphic(outputFile + ".png", getGraphic());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void checkConsistency() {

        int residents = residentAgents.size();
        int inside = insideAgents.size();
        int residentsStuckInside = residentStuckInsideAgents.size();
        int residentsStuckOutside = residentStuckOutsideAgents.size();
        //      int otherStuckInside = otherStuckInsideAgents.size();
        //      int otherStuckOutside = otherStuckOutsideAgents.size();

        int residentsInsideOrStuck = inside + residentsStuckInside + residentsStuckOutside;

        // check total number of counted agents
        if (residents != residentsInsideOrStuck) {
            StringBuffer sb = new StringBuffer();
            sb.append("Number of agents does not match: ");
            sb.append(residents);
            sb.append(" (residents) vs.");
            sb.append(residentsInsideOrStuck);
            sb.append(" (inside: ");
            sb.append(inside);
            sb.append(", stuckInside: ");
            sb.append(residentsStuckInside);
            sb.append(", stuckOutside: ");
            sb.append(residentsStuckOutside);
            sb.append(")");
            log.warn(sb.toString());

            for (Id id : residentAgents) {
                if (!insideAgents.contains(id) && !residentStuckInsideAgents.contains(id)
                        && !residentStuckOutsideAgents.contains(id))
                    log.warn("\tAgent " + id.toString() + " is a resident but not inside and not stuck.");
            }
            for (Id id : insideAgents) {
                if (!residentAgents.contains(id))
                    log.warn("\tAgent " + id.toString() + " is still inside but not a resident.");
            }
        }
    }

    @Override
    public void reset(int iteration) {

    }

    @Override
    public void handleEvent(PersonStuckEvent event) {
        // collect agents that got stuck
        if (insideAgents.remove(event.getPersonId())) {
            if (residentAgents.contains(event.getPersonId())) {
                residentStuckInsideAgents.add(event.getPersonId());
            } else
                otherStuckInsideAgents.add(event.getPersonId());
        } else {
            if (residentAgents.contains(event.getPersonId())) {
                residentStuckOutsideAgents.add(event.getPersonId());
            } else
                otherStuckOutsideAgents.add(event.getPersonId());
        }
    }

    @Override
    public void handleEvent(LinkLeaveEvent event) {
        checkTime(event);

        Id linkId = event.getLinkId();
        Link link = scenario.getNetwork().getLinks().get(linkId);

        boolean isInside = coordAnalyzer.isLinkAffected(link);

        if (isInside)
            insideAgents.remove(event.getPersonId());
    }

    @Override
    public void handleEvent(LinkEnterEvent event) {
        checkTime(event);

        Id linkId = event.getLinkId();
        Link link = scenario.getNetwork().getLinks().get(linkId);

        boolean isInside = coordAnalyzer.isLinkAffected(link);

        if (isInside)
            insideAgents.add(event.getPersonId());
    }

    @Override
    public void handleEvent(ActivityStartEvent event) {
        checkTime(event);

        Id facilityId = event.getFacilityId();
        Facility facility = scenario.getActivityFacilities().getFacilities().get(facilityId);

        boolean isInside = coordAnalyzer.isFacilityAffected(facility);

        if (isInside)
            insideAgents.add(event.getPersonId());
        else
            insideAgents.remove(event.getPersonId());
    }

    @Override
    public void handleEvent(ActivityEndEvent event) {
        checkTime(event);

        Id linkId = event.getLinkId();
        Link link = scenario.getNetwork().getLinks().get(linkId);

        boolean isInside = coordAnalyzer.isLinkAffected(link);

        if (isInside)
            insideAgents.add(event.getPersonId());
    }

    private void checkTime(Event event) {
        double eventTime = event.getTime();
        if (eventTime > currentSecond) {
            printStatistics();
            currentSecond = (int) eventTime;
        }
    }

    public void printInitialStatistics() {
        try {
            fos = new FileOutputStream(outputFile + "_statistics.txt.gz");
            gzos = new GZIPOutputStream(fos);
            osw = new OutputStreamWriter(gzos, charset);
            bw = new BufferedWriter(osw);

            bw.write("residental people");
            bw.write(separator);
            bw.write(String.valueOf(this.residentAgents.size()));
            bw.write(newLine);

            bw.write("residental households");
            bw.write(separator);
            bw.write(String.valueOf(this.residentHouseholds.size()));
            bw.write(newLine);

            // HHTP statistics
            bw.write(newLine);
            bw.write("household HHTP");
            bw.write(separator);
            bw.write("number of households");
            bw.write(newLine);
            for (Entry<Integer, List<Id>> entry : this.residentHouseholdHHTPs.entrySet()) {
                bw.write(String.valueOf(entry.getKey()));
                bw.write(separator);
                bw.write(String.valueOf(entry.getValue().size()));
                bw.write(newLine);
            }

            bw.close();
            osw.close();
            gzos.close();
            fos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void printStatistics() {
        try {
            int residents = 0;
            for (Id insideAgent : insideAgents) {
                if (residentAgents.contains(insideAgent))
                    residents++;
            }

            bw.write(String.valueOf(currentSecond));
            bw.write(separator);
            bw.write(String.valueOf(insideAgents.size()));
            bw.write(separator);
            bw.write(String.valueOf(residents));
            bw.write(separator);
            bw.write(String.valueOf(insideAgents.size() - residents));
            bw.write(newLine);

            if (currentSecond <= maxTime) {
                PlotData pd = new PlotData();
                pd.time = currentSecond;
                pd.residentAgentCount = residents;
                pd.commuterAgentCount = insideAgents.size() - residents;
                plotData.add(pd);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void writeGraphic(final String filename, JFreeChart chart) {
        try {
            ChartUtilities.saveChartAsPNG(new File(filename), chart, 1024, 768);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private JFreeChart getGraphic() {
        final XYSeriesCollection xyData = new XYSeriesCollection();
        final XYSeries insideSerie = new XYSeries("total inside area", false, true);
        final XYSeries residentsSerie = new XYSeries("residents inside area", false, true);
        final XYSeries commutersSerie = new XYSeries("commuters inside area", false, true);

        for (int i = 0; i < plotData.size(); i++) {
            PlotData pd = plotData.get(i);
            double hour = pd.time / 3600.0;
            insideSerie.add(hour, pd.commuterAgentCount + pd.residentAgentCount);
            residentsSerie.add(hour, pd.residentAgentCount);
            commutersSerie.add(hour, pd.commuterAgentCount);
        }
        xyData.addSeries(insideSerie);
        xyData.addSeries(residentsSerie);
        xyData.addSeries(commutersSerie);

        final JFreeChart chart = ChartFactory.createXYStepChart("agents inside area", "time [hour]", "# agents",
                xyData, PlotOrientation.VERTICAL, true, // legend
                false, // tooltips
                false // urls
        );

        XYPlot plot = chart.getXYPlot();

        NumberAxis na = new NumberAxis("time [hour]");
        na.setRange(0, maxTime / 3600.0);
        na.setLabelFont(plot.getRangeAxis().getLabelFont());
        na.setTickLabelFont(plot.getRangeAxis().getTickLabelFont());
        plot.setDomainAxis(na);
        return chart;
    }

    private static class PlotData {
        int time;
        int commuterAgentCount;
        int residentAgentCount;
    }
}