From 118952fb9a8f0d3ef32bf1e0c69d750043a056eb Mon Sep 17 00:00:00 2001 From: bhavyalatha26 Date: Wed, 14 Nov 2018 02:02:21 +0530 Subject: [PATCH] Bl/#837 output data documentation 4ci (#923) * new class to describe the fields in any output data file generated * new interface to define a stub to get output data descriptions for each class tht generates an output file * output data descriptors implemented for ModeChosenAnalysis * Merge branch 'master' into bl/#837-output-data-documentation-4ci # Conflicts: # src/main/java/beam/analysis/plots/ModeChosenAnalysis.java * output data descriptors implemented for ModeChosenAnalysis * new class to generate the data descriptions table and write it to an output file * data descriptions added for RealizedModeChoiceAnalysis and RideHailRevenueAnalysis * data descriptions added for PersonTravelTimeAnalysis * data descriptions added for FuelUsageAnalysis * data descriptions added for ExpectedMaxUtilityHeatMap * data descriptions added for physsim stats * data descriptions added for RideHailWaitingAnalysis * data descriptions added for RideHailWaitingAnalysis and Graph Surge Pricing * partial commit * data descriptions added for DeadHeadingAnalysis , summary stats , score stats and stop watch * data descriptions added for summarystats * data descriptions added for events * data descriptions added for rideHailTripDistanceOutputs, tripDurationOutputs, biasErrorGraphDataOutputs, biasNormalizedErrorGraphDataOutputs * Merge branch 'master' into bl/#837-output-data-documentation-4ci # Conflicts: # src/main/scala/beam/sim/config/BeamConfig.scala * use injected transport network while creating BeamMobsim instance in Output data description generator class --- ...PhyssimCalcLinkSpeedDistributionStats.java | 59 +-- .../physsim/PhyssimCalcLinkSpeedStats.java | 26 +- .../analysis/plots/DeadHeadingAnalysis.java | 25 +- .../analysis/plots/FuelUsageAnalysis.java | 50 ++- .../analysis/plots/GraphSurgePricing.java | 30 +- .../GraphsStatsAgentSimEventsListener.java | 6 +- .../analysis/plots/ModeChosenAnalysis.java | 67 ++- .../plots/PersonTravelTimeAnalysis.java | 20 +- .../analysis/plots/RealizedModeAnalysis.java | 20 +- .../plots/RideHailRevenueAnalysis.java | 22 +- .../plots/RideHailWaitingAnalysis.java | 32 +- .../RideHailingWaitingSingleAnalysis.java | 22 +- .../via/ExpectedMaxUtilityHeatMap.java | 28 +- .../java/beam/utils/OutputDataDescriptor.java | 12 + .../scala/beam/sim/BeamGraphComparator.scala | 1 - src/main/scala/beam/sim/BeamHelper.scala | 1 + src/main/scala/beam/sim/BeamMobsim.scala | 28 +- .../BeamOutputDataDescriptionGenerator.scala | 411 ++++++++++++++++++ src/main/scala/beam/sim/BeamSim.scala | 2 + .../beam/sim/OutputDataDescription.scala | 13 + 20 files changed, 783 insertions(+), 92 deletions(-) create mode 100644 src/main/java/beam/utils/OutputDataDescriptor.java create mode 100644 src/main/scala/beam/sim/BeamOutputDataDescriptionGenerator.scala create mode 100644 src/main/scala/beam/sim/OutputDataDescription.scala diff --git a/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedDistributionStats.java b/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedDistributionStats.java index 22906970a50..d61f6e25619 100644 --- a/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedDistributionStats.java +++ b/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedDistributionStats.java @@ -1,6 +1,9 @@ package beam.analysis.physsim; +import beam.analysis.plots.GraphsStatsAgentSimEventsListener; +import beam.sim.OutputDataDescription; import beam.sim.config.BeamConfig; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; @@ -20,9 +23,8 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.List; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -30,7 +32,7 @@ * @author Bhavya Latha Bandaru. * This class computes the distribution of free flow speed (in both m/s and %) over the network. */ -public class PhyssimCalcLinkSpeedDistributionStats { +public class PhyssimCalcLinkSpeedDistributionStats implements OutputDataDescriptor { private static int noOfBins = 24; private BeamConfig beamConfig; @@ -72,8 +74,8 @@ public void notifyIterationEnds(int iteration,TravelTimeCalculator travelTimeCal //If not running in test mode , write output to a csv file if (isNotTestMode()) { //write data outputs to CSV - this.writeCSV(speedDataMatrix,outputDirectoryHierarchy.getIterationFilename(iteration, outputAsSpeedUnitFileName+".csv"),"Free Speed Distribution(m/s)"); - this.writeCSV(processedSpeedDistributionAsPercentageData,outputDirectoryHierarchy.getIterationFilename(iteration, outputAsPercentageFileName+".csv"),"Free Speed Distribution(%)"); + this.writeCSV(speedDataMatrix,outputDirectoryHierarchy.getIterationFilename(iteration, outputAsSpeedUnitFileName+".csv"),"freeSpeedInMetersPerSecond"); + this.writeCSV(processedSpeedDistributionAsPercentageData,outputDirectoryHierarchy.getIterationFilename(iteration, outputAsPercentageFileName+".csv"),"linkEfficiencyInPercentage"); } //generate the required charts - frequency over speed (as m/s) generateSpeedDistributionBarChart(dataSetForSpeed,iteration); @@ -107,13 +109,13 @@ private CategoryDataset generateLinkEfficienciesDataSet(Map gen private void writeCSV(double[][] dataMatrix,String outputFilePath,String heading) { try { BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilePath)); - String completeHeading = heading + ",x-coordinate,y-coordinate\n"; + String completeHeading = heading + ",numberOfLinks\n"; bw.write(completeHeading); double[] data = dataMatrix[0]; IntStream.range(0,data.length) .forEach( i -> { try { - bw.write( i + "," + i + "," + data[i] + "\n"); + bw.write(i + "," + data[i] + "\n"); } catch (IOException e) { e.printStackTrace(); } @@ -133,7 +135,7 @@ private void writeCSV(double[][] dataMatrix,String outputFilePath,String heading private void writeCSV(Map dataMap,String outputFilePath,String heading) { try { BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilePath)); - String completeHeading = heading + ",x-coordinate,y-coordinate\n"; + String completeHeading = heading + ",linkEfficiencyRounded,numberOfLinks\n"; bw.write(completeHeading); dataMap.forEach((k,v) -> { try { @@ -172,15 +174,6 @@ public Map generateInputDataForFreeFlowSpeedGraph(int binsCoun return freeFlowSpeedFrequencies; } - public Stream getDistinctFreeSpeeds(int binsCount,Network network) { - return Stream.iterate(0, x -> x) - .limit(binsCount) - .flatMap(bin -> network.getLinks().values() - .stream() - .map(link -> link.getFreespeed(bin * 3600))) - .distinct(); - } - /** * Generates input data used to generate frequencies of link efficiencies * @return input generated data as map ( speed in m/s -> frequency ) @@ -188,8 +181,7 @@ public Stream getDistinctFreeSpeeds(int binsCount,Network network) { private Map generateInputDataForLinkEfficiencies(TravelTimeCalculator travelTimeCalculator) { int binSize = 3600; TravelTime travelTime = travelTimeCalculator.getLinkTravelTimes(); - Map frequencyOfEfficiencies = new HashMap<>(); - Map frequencyOfEfficiencies1 = new HashMap<>(); + Map frequencyOfEfficiencies = new HashMap<>(); //for each bin for (int idx = 0; idx < noOfBins; idx++) { //for each link @@ -200,13 +192,11 @@ private Map generateInputDataForLinkEfficiencies(TravelTimeCalc double averageSpeed = linkLength / averageTime; //calculate the average speed of the link double averageSpeedToFreeSpeedRatio = averageSpeed / freeSpeed; - Integer frequencyCount = frequencyOfEfficiencies.getOrDefault((int) Math.round(averageSpeedToFreeSpeedRatio*100),0); - Integer frequencyCount1 = frequencyOfEfficiencies1.getOrDefault(averageSpeedToFreeSpeedRatio*100,0); - frequencyOfEfficiencies.put((int) Math.round(averageSpeedToFreeSpeedRatio*100),frequencyCount+1); - frequencyOfEfficiencies1.put(averageSpeedToFreeSpeedRatio*100,frequencyCount1+1); + Integer frequencyCount1 = frequencyOfEfficiencies.getOrDefault(averageSpeedToFreeSpeedRatio*100,0); + frequencyOfEfficiencies.put(averageSpeedToFreeSpeedRatio*100,frequencyCount1+1); } } - return frequencyOfEfficiencies1; + return frequencyOfEfficiencies; } /** @@ -286,4 +276,23 @@ private void generateSpeedDistributionAsPercentageChart(CategoryDataset dataSet, } } + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String freeSpeedDistOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,outputAsSpeedUnitFileName + ".csv"); + String freeSpeedDistAsPercetnageOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,outputAsSpeedUnitFileName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String freeSpeedDistRelativePath = freeSpeedDistOutputFilePath.replace(outputDirPath, ""); + String freeSpeedDistAsPercetnageRelativePath = freeSpeedDistAsPercetnageOutputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistRelativePath, "freeSpeedInMetersPerSecond", "The possible full speed at which a vehicle can drive through the given link (in m/s)")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistRelativePath, "numberOfLinks", "Total number of links in the network that allow vehicles to travel with speeds up to the given free speed")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistAsPercetnageRelativePath, "linkEfficiencyInPercentage", "Average speed efficiency recorded by the the given network link in a day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistAsPercetnageRelativePath, "numberOfLinks", "Total number of links having the corresponding link efficiency")); + return list; + } } diff --git a/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedStats.java b/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedStats.java index 94cb699486e..6693d52c231 100644 --- a/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedStats.java +++ b/src/main/java/beam/analysis/physsim/PhyssimCalcLinkSpeedStats.java @@ -1,6 +1,9 @@ package beam.analysis.physsim; +import beam.analysis.plots.GraphsStatsAgentSimEventsListener; +import beam.sim.OutputDataDescription; import beam.sim.config.BeamConfig; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.*; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; @@ -25,7 +28,7 @@ * @author Bhavya Latha Bandaru. * This class computes the percentage of average speed over free speed for the network within a day. */ -public class PhyssimCalcLinkSpeedStats { +public class PhyssimCalcLinkSpeedStats implements OutputDataDescriptor { private static final List colors = new ArrayList<>(); private static int noOfBins = 24; @@ -74,7 +77,7 @@ public void notifyIterationEnds(int iteration, TravelTimeCalculator travelTimeCa private void writeCSV(Map processedData,String path) { try { BufferedWriter bw = new BufferedWriter(new FileWriter(path)); - String heading = "Bin,x-coordinate,y-coordinate\n"; + String heading = "Bin,AverageLinkSpeed\n"; bw.write(heading); for (int i = 0; i < processedData.size(); i++) { String line = String.valueOf(i) + "," + String.valueOf(i) + "," + String.valueOf(processedData.get(i)) + "\n"; @@ -139,8 +142,8 @@ private double[][] buildDataSetFromProcessedData(Map processedD private void generateAverageLinkSpeedGraph(CategoryDataset dataSet, int iterationNumber) { // Settings legend and title for the plot String plotTitle = "Average Link speed over a day"; - String x_axis = "Hour"; - String y_axis = "Average Link Speed %"; + String x_axis = "Bin"; + String y_axis = "AverageLinkSpeed"; int width = 800; int height = 600; @@ -213,4 +216,19 @@ public int getNumberOfBins() { return noOfBins; } + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String freeSpeedDistOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,outputFileName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String freeSpeedDistRelativePath = freeSpeedDistOutputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistRelativePath, "Bin", "A given time slot within a day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), freeSpeedDistRelativePath, "AverageLinkSpeed", "The average speed at which a vehicle can travel across the network during the given time bin")); + return list; + } } diff --git a/src/main/java/beam/analysis/plots/DeadHeadingAnalysis.java b/src/main/java/beam/analysis/plots/DeadHeadingAnalysis.java index 2a0625fed4c..e0742524603 100644 --- a/src/main/java/beam/analysis/plots/DeadHeadingAnalysis.java +++ b/src/main/java/beam/analysis/plots/DeadHeadingAnalysis.java @@ -7,6 +7,8 @@ import beam.analysis.plots.passengerpertrip.GenericPassengerPerTrip; import beam.analysis.plots.passengerpertrip.IGraphPassengerPerTrip; import beam.analysis.plots.passengerpertrip.TncPassengerPerTrip; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import com.google.common.base.CaseFormat; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; @@ -21,7 +23,7 @@ import java.io.IOException; import java.util.*; -public class DeadHeadingAnalysis implements GraphAnalysis { +public class DeadHeadingAnalysis implements GraphAnalysis, OutputDataDescriptor { private static final Integer TNC_MAX_PASSENGERS = 6; private static final Integer CAR_MAX_PASSENGERS = 4; private static final int METERS_IN_KM = 1000; @@ -30,6 +32,7 @@ public class DeadHeadingAnalysis implements GraphAnalysis { private static final String deadHeadingXAxisTitle = "Hour"; private static final String deadHeadingYAxisTitle = "# trips"; private static final String fileNameBase = "rideHail"; + private static final String dataFileBaseName = "rideHailStats"; private static final int DEFAULT_OCCURRENCE = 1; private static Map>> deadHeadingsMap = new HashMap<>(); private static Map> deadHeadingsTnc0Map = new HashMap<>(); @@ -721,7 +724,7 @@ public int getDeadHeadingTnc0HourDataCount(int hourIndex) { private void writeRideHailStatsCSV(IterationEndsEvent event) { - String csvFileName = event.getServices().getControlerIO().getOutputFilename("rideHailStats.csv"); + String csvFileName = event.getServices().getControlerIO().getOutputFilename(dataFileBaseName + ".csv"); try (BufferedWriter out = new BufferedWriter(new FileWriter(new File(csvFileName)))) { String heading = "Iteration,rideHailRevenue,averageRideHailWaitingTimeInSeconds,totalRideHailWaitingTimeInSeconds,passengerVKT,repositioningVKT,deadHeadingVKT,averageSurgePriceLevel,maxSurgePriceLevel,reservationCount"; @@ -807,4 +810,22 @@ private String getEventMode(Map attributes) { return attributes.get(PathTraversalEvent.ATTRIBUTE_MODE); } + @Override + public List getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(dataFileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "iterations", "iteration number")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "rideHailRevenue", "Revenue generated from ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "averageRideHailWaitingTimeInSeconds", "The average time spent by a passenger on waiting for hailing a ride")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "totalRideHailWaitingTimeInSeconds", "The total time spent by a passenger on waiting for hailing a ride")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "passengerVKT", "Kilometers travelled by the vehicle with a passenger")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "repositioningVKT", "Kilometers travelled by the vehicle to reposition to fleet")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "deadHeadingVKT", "Kilometers travelled by an empty vehicle towards the passenger")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "averageSurgePriceLevel", "The average value of surged price levels of ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "maxSurgePriceLevel", "The maximum value of surged price levels of ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "reservationCount", "Count of the number of passenger reservations made for the ride hail")); + return list; + } } diff --git a/src/main/java/beam/analysis/plots/FuelUsageAnalysis.java b/src/main/java/beam/analysis/plots/FuelUsageAnalysis.java index 87bf9addaab..0b07718e8e7 100644 --- a/src/main/java/beam/analysis/plots/FuelUsageAnalysis.java +++ b/src/main/java/beam/analysis/plots/FuelUsageAnalysis.java @@ -5,6 +5,8 @@ import beam.analysis.IterationSummaryAnalysis; import beam.analysis.PathTraversalSpatialTemporalTableGenerator; import beam.analysis.via.CSVWriter; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.data.category.CategoryDataset; @@ -18,11 +20,11 @@ import java.util.*; import java.util.stream.Collectors; -public class FuelUsageAnalysis implements GraphAnalysis, IterationSummaryAnalysis { +public class FuelUsageAnalysis implements GraphAnalysis, IterationSummaryAnalysis, OutputDataDescriptor { private static final String graphTitle = "Energy Use by Mode"; private static final String xAxisTitle = "Hour"; private static final String yAxisTitle = "Energy Use [MJ]"; - private static final String fileName = "energyUse.png"; + private static final String fileBaseName = "energyUse.png"; private Set modesFuel = new TreeSet<>(); private Map> hourModeFuelage = new HashMap<>(); private Map fuelConsumedByFuelType = new HashMap<>(); @@ -33,6 +35,22 @@ public FuelUsageAnalysis(StatsComputation this.statsComputation = statsComputation; } + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,fileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "Modes", "Mode of travel chosen by the passenger")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "Bin_*", "Energy consumed by the vehicle while travelling by the chosen mode within the given time bin")); + return list; + } + public static class FuelUsageStatsComputation implements StatsComputation>, Set>, double[][]> { @Override public double[][] compute(Tuple>, Set> stat) { @@ -134,12 +152,12 @@ private void processFuelUsage(Event event) { private void createModesFuelageGraph(CategoryDataset dataset, int iterationNumber) throws IOException { - final JFreeChart chart = GraphUtils.createStackedBarChartWithDefaultSettings(dataset, graphTitle, xAxisTitle, yAxisTitle, fileName, true); + final JFreeChart chart = GraphUtils.createStackedBarChartWithDefaultSettings(dataset, graphTitle, xAxisTitle, yAxisTitle, fileBaseName, true); CategoryPlot plot = chart.getCategoryPlot(); List modesFuelList = new ArrayList<>(modesFuel); Collections.sort(modesFuelList); GraphUtils.plotLegendItems(plot, modesFuelList, dataset.getRowCount()); - String graphImageFile = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileName); + String graphImageFile = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileBaseName); GraphUtils.saveJFreeChartAsPNG(chart, graphImageFile, GraphsStatsAgentSimEventsListener.GRAPH_WIDTH, GraphsStatsAgentSimEventsListener.GRAPH_HEIGHT); } @@ -153,54 +171,42 @@ public Map getSummaryStats() { private void createFuelCSV(Map> hourModeFuelage, int iterationNumber) { - String SEPERATOR = ","; + String SEPARATOR = ","; - CSVWriter csvWriter = new CSVWriter(GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, "energyUse.csv")); + CSVWriter csvWriter = new CSVWriter(GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileBaseName + ".csv")); BufferedWriter bufferedWriter = csvWriter.getBufferedWriter(); - - List hours = GraphsStatsAgentSimEventsListener.getSortedIntegerList(hourModeFuelage.keySet()); List modesFuelList = GraphsStatsAgentSimEventsListener.getSortedStringList(modesFuel); int maxHour = hours.get(hours.size() - 1); - //double[][] dataset = new double[modesFuel.size()][maxHour + 1]; - try { - - bufferedWriter.append("Modes"); - bufferedWriter.append(SEPERATOR); + bufferedWriter.append(SEPARATOR); for (int j = 0; j < maxHour; j++) { bufferedWriter.append("Bin_") .append(String.valueOf(j)) - .append(SEPERATOR); + .append(SEPARATOR); } bufferedWriter.append("\n"); - for (String modeChosen : modesFuelList) { bufferedWriter.append(modeChosen); - bufferedWriter.append(SEPERATOR); + bufferedWriter.append(SEPARATOR); for (int j = 0; j < maxHour; j++) { Map modesData = hourModeFuelage.get(j); - - String modeHourValue = "0"; - if (modesData != null) { if (modesData.get(modeChosen) != null) { modeHourValue = modesData.get(modeChosen).toString(); } } - bufferedWriter.append(modeHourValue); - bufferedWriter.append(SEPERATOR); + bufferedWriter.append(SEPARATOR); } bufferedWriter.append("\n"); } bufferedWriter.flush(); csvWriter.closeFile(); - } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/beam/analysis/plots/GraphSurgePricing.java b/src/main/java/beam/analysis/plots/GraphSurgePricing.java index a99a55be4a7..9a0059ef635 100755 --- a/src/main/java/beam/analysis/plots/GraphSurgePricing.java +++ b/src/main/java/beam/analysis/plots/GraphSurgePricing.java @@ -2,6 +2,8 @@ import beam.agentsim.agents.ridehail.RideHailSurgePricingManager; import beam.agentsim.agents.ridehail.SurgePriceBin; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import com.google.inject.Inject; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; @@ -31,7 +33,7 @@ import static java.util.stream.IntStream.range; -public class GraphSurgePricing implements ControlerListener, IterationEndsListener { +public class GraphSurgePricing implements ControlerListener, IterationEndsListener, OutputDataDescriptor { // The keys of the outer map represents binNumber // The inner map consists of category index to number of occurrence for each category @@ -541,4 +543,30 @@ private void drawHistogram(double[][] dataset, List categoriesList, bool ioe.printStackTrace(); } } + + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String surgePricingOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"rideHailSurgePriceLevel.csv"); + String revenueOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"rideHailRevenue.csv"); + String surgePricingAndRevenueOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"tazRideHailSurgePriceLevel.csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String surgePricingRelativePath = surgePricingOutputFilePath.replace(outputDirPath, ""); + String revenueRelativePath = revenueOutputFilePath.replace(outputDirPath, ""); + String surgePricingAndRevenueRelativePath = surgePricingAndRevenueOutputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingRelativePath, "PriceLevel", "Travel fare charged by the ride hail in the given hour")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingRelativePath, "Hour", "Hour of the day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), revenueRelativePath, "Revenue", "Revenue earned by ride hail in the given hour")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), revenueRelativePath, "Hour", "Hour of the day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingAndRevenueRelativePath, "TazId", "TAZ id")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingAndRevenueRelativePath, "DataType", "Type of data , can be \"priceLevel\" or \"revenue\"")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingAndRevenueRelativePath, "Value", "Value of the given data type , can indicate either price Level or revenue earned by the ride hail in the given hour")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), surgePricingAndRevenueRelativePath, "Hour", "Hour of the day")); + return list; + } } diff --git a/src/main/java/beam/analysis/plots/GraphsStatsAgentSimEventsListener.java b/src/main/java/beam/analysis/plots/GraphsStatsAgentSimEventsListener.java index c8a36522bb4..56681d3e3cb 100755 --- a/src/main/java/beam/analysis/plots/GraphsStatsAgentSimEventsListener.java +++ b/src/main/java/beam/analysis/plots/GraphsStatsAgentSimEventsListener.java @@ -100,10 +100,10 @@ public void createGraphs(IterationEndsEvent event) throws IOException { // TODO: Asif - benchmarkFileLoc also part of calibraiton yml -> remove there (should be just in config file) // TODO: Asif there should be no need to write to root and then read (just quick hack) -> update interface on methods, which need that data to pass in memory - BeamAnalysis modeChoseStats = statsFactory.getAnalysis(StatsType.ModeChosen); - ((ModeChosenAnalysis) modeChoseStats).writeToRootCSV(); + ModeChosenAnalysis modeChoseStats = (ModeChosenAnalysis) statsFactory.getAnalysis(StatsType.ModeChosen); + modeChoseStats.writeToRootCSV(ModeChosenAnalysis.getModeChoiceFileBaseName()); if (beamConfig.beam().calibration().mode().benchmarkFileLoc().trim().length() > 0) { - String outPath = CONTROLLER_IO.getOutputFilename("modeChoice.csv"); + String outPath = CONTROLLER_IO.getOutputFilename(ModeChosenAnalysis.getModeChoiceFileBaseName() + ".csv"); Double modesAbsoluteError = new ModeChoiceObjectiveFunction(beamConfig.beam().calibration().mode().benchmarkFileLoc()) .evaluateFromRun(outPath, ErrorComparisonType.AbsoluteError()); log.info("modesAbsoluteError: " + modesAbsoluteError); diff --git a/src/main/java/beam/analysis/plots/ModeChosenAnalysis.java b/src/main/java/beam/analysis/plots/ModeChosenAnalysis.java index 5d3996b89c5..e2c3da30343 100644 --- a/src/main/java/beam/analysis/plots/ModeChosenAnalysis.java +++ b/src/main/java/beam/analysis/plots/ModeChosenAnalysis.java @@ -2,8 +2,10 @@ import beam.agentsim.events.ModeChoiceEvent; import beam.analysis.via.CSVWriter; +import beam.sim.OutputDataDescription; import beam.sim.config.BeamConfig; import beam.sim.metrics.MetricsSupport; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.data.category.CategoryDataset; @@ -23,12 +25,14 @@ import static beam.sim.metrics.Metrics.ShortLevel; import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; -public class ModeChosenAnalysis implements GraphAnalysis, MetricsSupport { +public class ModeChosenAnalysis implements GraphAnalysis, MetricsSupport , OutputDataDescriptor { + private static final String graphTitle = "Mode Choice Histogram"; private static final String graphTitleBenchmark = "Reference Mode Choice Histogram"; private static final String xAxisTitle = "Hour"; private static final String yAxisTitle = "# mode chosen"; - private static final String fileName = "modeChoice"; + private static final String modeChoiceFileBaseName = "modeChoice"; + private static final String referenceModeChoiceFileBaseName = "referenceModeChoice"; private final Set iterationTypeSet = new HashSet<>(); private final Map> modeChoiceInIteration = new HashMap<>(); @@ -42,6 +46,31 @@ public class ModeChosenAnalysis implements GraphAnalysis, MetricsSupport { private final StatsComputation>, Set>, double[][]> statComputation; + @Override + public List getOutputDataDescriptions() { + String modeChoiceOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(modeChoiceFileBaseName + ".csv"); + String referenceModeChoiceOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(referenceModeChoiceFileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String modeChoiceRelativePath = modeChoiceOutputFilePath.replace(outputDirPath, ""); + String referenceModeChoiceRelativePath = referenceModeChoiceOutputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "iterations", "iteration number")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "car", "Car chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "drive_transit", "Drive to transit chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "ride_hail", "Ride Hail chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "walk", "Walk chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), modeChoiceRelativePath, "walk_transit", "Walk to transit chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "iterations", "Bike chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "bike", "iteration number")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "car", "Car chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "drive_transit", "Drive to transit chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "ride_hail", "Ride Hail chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "ride_hail_transit", "Ride Hail to transit chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "walk", "Walk chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), referenceModeChoiceRelativePath, "walk_transit", "Walk to transit chosen as travel mode")); + return list; + } + public static class ModeChosenComputation implements StatsComputation>, Set>, double[][]> { @Override @@ -78,6 +107,10 @@ public ModeChosenAnalysis(StatsComputation(hourModeFrequency, modesChosen)); } - private void createModesFrequencyGraph(CategoryDataset dataset, int iterationNumber) throws IOException { - final JFreeChart chart = GraphUtils.createStackedBarChartWithDefaultSettings(dataset, graphTitle, xAxisTitle, yAxisTitle, fileName, true); + private void createModesFrequencyGraph(CategoryDataset dataset, int iterationNumber, String fileBaseName) throws IOException { + final JFreeChart chart = GraphUtils.createStackedBarChartWithDefaultSettings(dataset, graphTitle, xAxisTitle, yAxisTitle, fileBaseName, true); CategoryPlot plot = chart.getCategoryPlot(); List modesChosenList = new ArrayList<>(modesChosen); Collections.sort(modesChosenList); GraphUtils.plotLegendItems(plot, modesChosenList, dataset.getRowCount()); - String graphImageFile = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileName + ".png"); + String graphImageFile = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileBaseName + ".png"); GraphUtils.saveJFreeChartAsPNG(chart, graphImageFile, GraphsStatsAgentSimEventsListener.GRAPH_WIDTH, GraphsStatsAgentSimEventsListener.GRAPH_HEIGHT); } - private void createModeChosenCSV(Map> hourModeChosen, int iterationNumber) { + private void createModeChosenCSV(Map> hourModeChosen, int iterationNumber,String fileBaseName) { final String separator = ","; - CSVWriter csvWriter = new CSVWriter(GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileName + ".csv")); + CSVWriter csvWriter = new CSVWriter(GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iterationNumber, fileBaseName + ".csv")); BufferedWriter bufferedWriter = csvWriter.getBufferedWriter(); List hours = GraphsStatsAgentSimEventsListener.getSortedIntegerList(hourModeChosen.keySet()); @@ -315,9 +348,9 @@ private void createGraphInRootDirectory(CategoryDataset dataset, String graphTit } // csv for root modeChoice.png - void writeToRootCSV() { + void writeToRootCSV(String fileBaseName) { - String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename("modeChoice.csv"); + String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(fileBaseName + ".csv"); try (final BufferedWriter out = new BufferedWriter(new FileWriter(new File(csvFileName)))) { @@ -355,9 +388,9 @@ void writeToRootCSV() { } //csv for reference mode choice - public void writeToRootCSVForReference() { + public void writeToRootCSVForReference(String fileBaseName) { - String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename("referenceModeChoice.csv"); + String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(fileBaseName + ".csv"); try (final BufferedWriter out = new BufferedWriter(new FileWriter(new File(csvFileName)))) { diff --git a/src/main/java/beam/analysis/plots/PersonTravelTimeAnalysis.java b/src/main/java/beam/analysis/plots/PersonTravelTimeAnalysis.java index 02533d0807c..ff666876100 100644 --- a/src/main/java/beam/analysis/plots/PersonTravelTimeAnalysis.java +++ b/src/main/java/beam/analysis/plots/PersonTravelTimeAnalysis.java @@ -1,6 +1,8 @@ package beam.analysis.plots; import beam.analysis.IterationSummaryAnalysis; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.data.category.CategoryDataset; @@ -21,11 +23,12 @@ import java.util.*; import java.util.stream.Collectors; -public class PersonTravelTimeAnalysis implements GraphAnalysis, IterationSummaryAnalysis { +public class PersonTravelTimeAnalysis implements GraphAnalysis, IterationSummaryAnalysis, OutputDataDescriptor { private static final int SECONDS_IN_MINUTE = 60; private static final String xAxisTitle = "Hour"; private static final String yAxisTitle = "Average Travel Time [min]"; private static final String otherMode = "others"; + private final String fileBaseName = "averageTravelTimes"; private Map, PersonDepartureEvent>> personLastDepartureEvents = new HashMap<>(); private Map>> hourlyPersonTravelTimes = new HashMap<>(); @@ -35,6 +38,17 @@ public PersonTravelTimeAnalysis(StatsComputation getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,fileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "Mode", "Travel mode chosen")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "Hour,*", "Average time taken to travel by the chosen mode during the given hour of the day")); + return list; + } + public static class PersonTravelTimeComputation implements StatsComputation>>, Tuple, double[][]>> { @Override @@ -98,7 +112,7 @@ Tuple, double[][]> compute() { private void createCSV(Tuple, double[][]> data, int iteration) { List modes = data.getFirst(); double[][] dataSets = data.getSecond(); - String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iteration, "averageTravelTimes.csv"); + String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iteration, fileBaseName + ".csv"); try (BufferedWriter out = new BufferedWriter(new FileWriter(new File(csvFileName)))) { StringBuilder heading = new StringBuilder("TravelTimeMode\\Hour"); int hours = Arrays.stream(dataSets).mapToInt(value -> value.length).max().orElse(dataSets[0].length); @@ -224,7 +238,7 @@ private void processPersonDepartureEvent(Event event) { } private void createAverageTimesGraph(CategoryDataset dataset, int iterationNumber, String mode) throws IOException { - String fileName = "averageTravelTimes" + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, mode) + ".png"; + String fileName = fileBaseName + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, mode) + ".png"; String graphTitle = "Average Travel Time [" + mode + "]"; final JFreeChart chart = GraphUtils.createStackedBarChartWithDefaultSettings(dataset, graphTitle, xAxisTitle, yAxisTitle, fileName, false); diff --git a/src/main/java/beam/analysis/plots/RealizedModeAnalysis.java b/src/main/java/beam/analysis/plots/RealizedModeAnalysis.java index 630130d8343..b825b1ee6e5 100644 --- a/src/main/java/beam/analysis/plots/RealizedModeAnalysis.java +++ b/src/main/java/beam/analysis/plots/RealizedModeAnalysis.java @@ -2,7 +2,9 @@ import beam.agentsim.events.ModeChoiceEvent; import beam.agentsim.events.ReplanningEvent; +import beam.sim.OutputDataDescription; import beam.sim.metrics.MetricsSupport; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.data.category.CategoryDataset; @@ -25,7 +27,7 @@ import static beam.sim.metrics.Metrics.ShortLevel; -public class RealizedModeAnalysis implements GraphAnalysis, MetricsSupport { +public class RealizedModeAnalysis implements GraphAnalysis, MetricsSupport , OutputDataDescriptor { private static final String graphTitle = "Realized Mode Histogram"; @@ -47,6 +49,22 @@ public RealizedModeAnalysis(StatsComputation getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(fileName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "iterations", "iteration number")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "car", "Car chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "drive_transit", "Drive to transit chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "other", "Other modes of travel chosen")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "ride_hail", "Ride Hail chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "walk", "Walk chosen as travel mode")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "walk_transit", "Walk to transit chosen as travel mode")); + return list; + } + public static class RealizedModesStatsComputation implements StatsComputation>, Set>, double[][]> { @Override diff --git a/src/main/java/beam/analysis/plots/RideHailRevenueAnalysis.java b/src/main/java/beam/analysis/plots/RideHailRevenueAnalysis.java index 48ddcb60dc5..fa6754f64c0 100755 --- a/src/main/java/beam/analysis/plots/RideHailRevenueAnalysis.java +++ b/src/main/java/beam/analysis/plots/RideHailRevenueAnalysis.java @@ -2,6 +2,8 @@ import beam.agentsim.agents.ridehail.RideHailSurgePricingManager; import beam.analysis.plots.modality.RideHailDistanceRowModel; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import com.google.inject.Inject; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; @@ -18,12 +20,15 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import static beam.analysis.AnalysisCollector.rideHailRevenueAnalytics; -public class RideHailRevenueAnalysis implements ControlerListener, IterationEndsListener { +public class RideHailRevenueAnalysis implements ControlerListener, IterationEndsListener, OutputDataDescriptor { private RideHailSurgePricingManager surgePricingManager; + private String fileBaseName = "rideHailRevenue"; private OutputDirectoryHierarchy outputDirectoryHiearchy; @@ -71,7 +76,7 @@ private void drawRideHailRevenueGraph(DefaultCategoryDataset dataSet) { PlotOrientation.VERTICAL, false, true, false); - String graphImageFile = outputDirectoryHiearchy.getOutputFilename("rideHailRevenue.png"); + String graphImageFile = outputDirectoryHiearchy.getOutputFilename(fileBaseName + ".png"); try { GraphUtils.saveJFreeChartAsPNG(chart, graphImageFile, GraphsStatsAgentSimEventsListener.GRAPH_WIDTH, GraphsStatsAgentSimEventsListener.GRAPH_HEIGHT); } catch (IOException e) { @@ -94,7 +99,7 @@ private DefaultCategoryDataset createDataset(ArrayBuffer data) { private void writeRideHailRevenueCsv(ArrayBuffer data) { try { - String fileName = outputDirectoryHiearchy.getOutputFilename("rideHailRevenue.csv"); + String fileName = outputDirectoryHiearchy.getOutputFilename(fileBaseName + ".csv"); BufferedWriter out = new BufferedWriter(new FileWriter(new File(fileName))); out.write("iteration #,revenue"); @@ -119,4 +124,15 @@ private void writeRideHailRevenueCsv(ArrayBuffer data) { e.printStackTrace(); } } + + @Override + public List getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename(fileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "iteration #", "iteration number")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "revenue", "Revenue generated from ride hail")); + return list; + } } diff --git a/src/main/java/beam/analysis/plots/RideHailWaitingAnalysis.java b/src/main/java/beam/analysis/plots/RideHailWaitingAnalysis.java index 4cebf212ee3..7ded091e56b 100644 --- a/src/main/java/beam/analysis/plots/RideHailWaitingAnalysis.java +++ b/src/main/java/beam/analysis/plots/RideHailWaitingAnalysis.java @@ -2,7 +2,9 @@ import beam.agentsim.events.ModeChoiceEvent; import beam.analysis.plots.modality.RideHailDistanceRowModel; +import beam.sim.OutputDataDescription; import beam.sim.config.BeamConfig; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.data.category.CategoryDataset; @@ -24,13 +26,13 @@ /** * @author abid */ -public class RideHailWaitingAnalysis implements GraphAnalysis { +public class RideHailWaitingAnalysis implements GraphAnalysis, OutputDataDescriptor { public RideHailWaitingAnalysis(StatsComputation, Map>>, Tuple>, double[][]>> statComputation) { this.statComputation = statComputation; } - public static class WaitingStatsComputation implements StatsComputation, Map>>, Tuple>, double[][]>> { + public static class WaitingStatsComputation implements StatsComputation, Map>>, Tuple>, double[][]>> { @Override public Tuple>, double[][]> compute(Tuple, Map>> stat) { @@ -118,6 +120,7 @@ private double[][] buildModesFrequencyDataset(Map> private static final String xAxisTitle = "Hour"; private static final String yAxisTitle = "Waiting Time (frequencies)"; private static final String fileName = "rideHailWaitingStats"; + private static final String rideHailIndividualWaitingTimesFileBaseName = "rideHailIndividualWaitingTimes"; private List rideHailWaitingIndividualStatList = new ArrayList<>(); private Map rideHailWaiting = new HashMap<>(); private Map> hoursTimesMap = new HashMap<>(); @@ -214,7 +217,7 @@ public void createGraph(IterationEndsEvent event) throws IOException { private void writeRideHailWaitingIndividualStatCSV(int iteration) { - String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iteration, "rideHailIndividualWaitingTimes.csv"); + String csvFileName = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iteration, rideHailIndividualWaitingTimesFileBaseName + ".csv"); try (BufferedWriter out = new BufferedWriter(new FileWriter(new File(csvFileName)))) { String heading = "timeOfDayInSeconds,personId,rideHailVehicleId,waitingTimeInSeconds"; @@ -336,6 +339,29 @@ private List getLegends(List categories) { return legends; } + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String rideHailWaitingStatsOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,fileName + ".csv"); + String rideHailIndividualWaitingTimesOutputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,rideHailIndividualWaitingTimesFileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String rideHailWaitingStatsRelativePath = rideHailWaitingStatsOutputFilePath.replace(outputDirPath, ""); + String rideHailIndividualWaitingTimesRelativePath = rideHailIndividualWaitingTimesOutputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailWaitingStatsRelativePath, "Waiting Time", "The time spent by a passenger waiting for a ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailWaitingStatsRelativePath, "Hour", "Hour of the day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailWaitingStatsRelativePath, "Count", "Frequencies of times spent waiting for a ride hail during the entire day")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailIndividualWaitingTimesRelativePath, "timeOfDayInSeconds", "Time of a day in seconds")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailIndividualWaitingTimesRelativePath, "personId", "Unique id of the passenger travelling by the ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailIndividualWaitingTimesRelativePath, "rideHailVehicleId", "Unique id of the ride hail vehicle")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), rideHailIndividualWaitingTimesRelativePath, "waitingTimeInSeconds", "Time spent by the given passenger waiting for the arrival of the given ride hailing vehicle")); + return list; + } + private double getRoundedCategoryUpperBound(double category) { return Math.round(category * 100) / 100.0; } diff --git a/src/main/java/beam/analysis/plots/RideHailingWaitingSingleAnalysis.java b/src/main/java/beam/analysis/plots/RideHailingWaitingSingleAnalysis.java index 4365c5175fa..1ffeb0f8469 100644 --- a/src/main/java/beam/analysis/plots/RideHailingWaitingSingleAnalysis.java +++ b/src/main/java/beam/analysis/plots/RideHailingWaitingSingleAnalysis.java @@ -1,8 +1,10 @@ package beam.analysis.plots; import beam.agentsim.events.ModeChoiceEvent; +import beam.sim.OutputDataDescription; import beam.sim.config.BeamConfig; import beam.utils.DebugLib; +import beam.utils.OutputDataDescriptor; import org.jfree.chart.JFreeChart; import org.jfree.data.category.CategoryDataset; import org.jfree.data.general.DatasetUtilities; @@ -17,13 +19,15 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** * @author abid */ -public class RideHailingWaitingSingleAnalysis implements GraphAnalysis { +public class RideHailingWaitingSingleAnalysis implements GraphAnalysis, OutputDataDescriptor { private static final String graphTitle = "Ride Hail Waiting Time"; private static final String xAxisTitle = "Hour"; @@ -36,6 +40,22 @@ public class RideHailingWaitingSingleAnalysis implements GraphAnalysis { private Map hoursTimesMap = new HashMap<>(); private final StatsComputation, double[][]> statComputation; + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,fileName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "WaitingTime(sec)", "Time spent by a passenger on waiting for a ride hail")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "Hour*", "Hour of the day")); + return list; + } + public static class RideHailingWaitingSingleComputation implements StatsComputation, double[][]> { @Override diff --git a/src/main/java/beam/analysis/via/ExpectedMaxUtilityHeatMap.java b/src/main/java/beam/analysis/via/ExpectedMaxUtilityHeatMap.java index 4395c402dd4..6eb7251870b 100755 --- a/src/main/java/beam/analysis/via/ExpectedMaxUtilityHeatMap.java +++ b/src/main/java/beam/analysis/via/ExpectedMaxUtilityHeatMap.java @@ -1,6 +1,9 @@ package beam.analysis.via; import beam.agentsim.events.ModeChoiceEvent; +import beam.analysis.plots.GraphsStatsAgentSimEventsListener; +import beam.sim.OutputDataDescription; +import beam.utils.OutputDataDescriptor; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.events.Event; import org.matsim.api.core.v01.network.Link; @@ -11,15 +14,18 @@ import java.io.BufferedWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; -public class ExpectedMaxUtilityHeatMap implements BasicEventHandler { +public class ExpectedMaxUtilityHeatMap implements BasicEventHandler, OutputDataDescriptor { private final String SEPERATOR = ","; private final Network network; private final OutputDirectoryHierarchy controlerIO; private final int writeEventsInterval; private CSVWriter csvWriter; + private final String fileBaseName= "expectedMaxUtilityHeatMap"; private BufferedWriter bufferedWriter; private boolean writeDataInThisIteration = false; @@ -82,9 +88,27 @@ public void reset(int iteration) { writeDataInThisIteration = writeEventsInterval > 0 && iteration % writeEventsInterval == 0; if (writeDataInThisIteration) { - this.csvWriter = new CSVWriter(controlerIO.getIterationFilename(iteration, "expectedMaxUtilityHeatMap.csv")); + this.csvWriter = new CSVWriter(controlerIO.getIterationFilename(iteration, fileBaseName + ".csv")); this.bufferedWriter = this.csvWriter.getBufferedWriter(); printColumnHeaders(); } } + + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + @Override + public List getOutputDataDescriptions() { + String outputFilePath = controlerIO.getIterationFilename(0, fileBaseName + ".csv"); + String outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath(); + String relativePath = outputFilePath.replace(outputDirPath, ""); + List list = new ArrayList<>(); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "time", "Time of the event occurrence")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "x", "X co-ordinate of the network link location")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "y", "Y co-ordinate of the network link location")); + list.add(new OutputDataDescription(this.getClass().getSimpleName(), relativePath, "expectedMaximumUtility", "Expected maximum utility of the network link for the event")); + return list; + } } diff --git a/src/main/java/beam/utils/OutputDataDescriptor.java b/src/main/java/beam/utils/OutputDataDescriptor.java new file mode 100644 index 00000000000..be25afaac20 --- /dev/null +++ b/src/main/java/beam/utils/OutputDataDescriptor.java @@ -0,0 +1,12 @@ +package beam.utils; + +import beam.sim.OutputDataDescription; +import java.util.List; + +public interface OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * @return list of data description objects + */ + List getOutputDataDescriptions(); +} diff --git a/src/main/scala/beam/sim/BeamGraphComparator.scala b/src/main/scala/beam/sim/BeamGraphComparator.scala index 6c5d468c0cf..7dd804509b2 100644 --- a/src/main/scala/beam/sim/BeamGraphComparator.scala +++ b/src/main/scala/beam/sim/BeamGraphComparator.scala @@ -16,7 +16,6 @@ import scala.xml.{Elem, NodeBuffer} */ object BeamGraphComparator { - /** * Generates the html page for graph comparison * @param files Map that maps file name to the absolute file path across all iterations. diff --git a/src/main/scala/beam/sim/BeamHelper.scala b/src/main/scala/beam/sim/BeamHelper.scala index 8e7ac1b3eeb..ac2ee7f96fa 100755 --- a/src/main/scala/beam/sim/BeamHelper.scala +++ b/src/main/scala/beam/sim/BeamHelper.scala @@ -191,6 +191,7 @@ trait BeamHelper extends LazyLogging { addControlerListenerBinding().to(classOf[BeamSim]) addControlerListenerBinding().to(classOf[GraphSurgePricing]) + bind(classOf[BeamOutputDataDescriptionGenerator]) addControlerListenerBinding().to(classOf[RideHailRevenueAnalysis]) bindMobsim().to(classOf[BeamMobsim]) diff --git a/src/main/scala/beam/sim/BeamMobsim.scala b/src/main/scala/beam/sim/BeamMobsim.scala index a4f9d81f605..d3cf7c8c066 100755 --- a/src/main/scala/beam/sim/BeamMobsim.scala +++ b/src/main/scala/beam/sim/BeamMobsim.scala @@ -2,7 +2,8 @@ package beam.sim import java.awt.Color import java.lang.Double -import java.util.Random +import java.util +import java.util.{ArrayList, List, Random} import java.util.concurrent.TimeUnit import java.util.stream.Stream @@ -21,6 +22,7 @@ import beam.agentsim.infrastructure.ParkingManager.ParkingStockAttributes import beam.agentsim.infrastructure.ZonalParkingManager import beam.agentsim.scheduler.BeamAgentScheduler import beam.agentsim.scheduler.BeamAgentScheduler.{CompletionNotice, ScheduleTrigger, StartSchedule} +import beam.analysis.plots.GraphsStatsAgentSimEventsListener import beam.router.BeamRouter.InitTransit import beam.sim.metrics.MetricsSupport import beam.sim.monitoring.ErrorListener @@ -56,7 +58,7 @@ class BeamMobsim @Inject()( val rideHailSurgePricingManager: RideHailSurgePricingManager ) extends Mobsim with LazyLogging - with MetricsSupport { + with MetricsSupport with OutputDataDescriptor { private implicit val timeout: Timeout = Timeout(50000, TimeUnit.SECONDS) var memoryLoggingTimerActorRef: ActorRef = _ @@ -68,6 +70,8 @@ class BeamMobsim @Inject()( var debugActorWithTimerActorRef: ActorRef = _ var debugActorWithTimerCancellable: Cancellable = _ + + final val fileBaseName = "rideHailInitialLocation" /* var rideHailSurgePricingManager: RideHailSurgePricingManager = injector.getInstance(classOf[BeamServices]) new RideHailSurgePricingManager(beamServices.beamConfig,beamServices.taz);*/ @@ -340,11 +344,11 @@ class BeamMobsim @Inject()( if (beamServices.matsimServices != null) { rideHailinitialLocationSpatialPlot.writeCSV( beamServices.matsimServices.getControlerIO - .getIterationFilename(beamServices.iterationNumber, "rideHailInitialLocation.csv") + .getIterationFilename(beamServices.iterationNumber, fileBaseName+".csv") ) rideHailinitialLocationSpatialPlot.writeImage( beamServices.matsimServices.getControlerIO - .getIterationFilename(beamServices.iterationNumber, "rideHailinitialLocation.png") + .getIterationFilename(beamServices.iterationNumber, fileBaseName+".png") ) } log.info("Initialized {} people", beamServices.personRefs.size) @@ -453,4 +457,20 @@ class BeamMobsim @Inject()( logger.info("Processing Agentsim Events (End)") } + + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0, fileBaseName + ".csv") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName, relativePath, "rideHailAgentID", "Unique id of the given ride hail agent")) + list.add(OutputDataDescription(this.getClass.getSimpleName, relativePath, "xCoord", "X co-ordinate of the starting location of the ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName, relativePath, "yCoord", "Y co-ordinate of the starting location of the ride hail")) + list + } } diff --git a/src/main/scala/beam/sim/BeamOutputDataDescriptionGenerator.scala b/src/main/scala/beam/sim/BeamOutputDataDescriptionGenerator.scala new file mode 100644 index 00000000000..40afbdb1102 --- /dev/null +++ b/src/main/scala/beam/sim/BeamOutputDataDescriptionGenerator.scala @@ -0,0 +1,411 @@ +package beam.sim + +import java.io.{BufferedWriter, FileWriter, IOException} + +import akka.actor.ActorSystem +import beam.agentsim.agents.ridehail.RideHailSurgePricingManager +import beam.analysis.physsim.{PhyssimCalcLinkSpeedDistributionStats, PhyssimCalcLinkSpeedStats} +import beam.analysis.plots._ +import beam.analysis.via.ExpectedMaxUtilityHeatMap +import beam.utils.OutputDataDescriptor +import com.conveyal.r5.transit.TransportNetwork +import com.google.inject.Inject +import org.matsim.api.core.v01.Scenario +import org.matsim.core.api.experimental.events.EventsManager +import org.matsim.core.controler.events.ControlerEvent + +import scala.collection.JavaConverters._ + +/** + * Generate data descriptions table for all output file generating classes. + */ +class BeamOutputDataDescriptionGenerator @Inject() +(private val actorSystem: ActorSystem, + private val transportNetwork: TransportNetwork, + private val beamServices: BeamServices, + private val eventsManager: EventsManager, + private val scenario: Scenario) { + + private final val outputFileName = "dataDescriptors.csv" + private final val outputFileHeader = "ClassName,OutputFile,Field,Description\n" + + /** + * Generates the data descriptors and writes them to the output file. + * @param event a controller event + */ + def generateDescriptors(event : ControlerEvent): Unit = { + //get all the required class file instances + val descriptors: Seq[OutputDataDescription] = getClassesGeneratingOutputs(event) flatMap { classRef => + classRef.getOutputDataDescriptions.asScala.toList + } + //generate csv from the data objects + val descriptionsAsCSV = descriptors map { d => + d.asInstanceOf[Product].productIterator mkString "," + } mkString "\n" + //write the generated csv to an external file in the output folder + val filePath = event.getServices.getControlerIO.getOutputPath + "/" + outputFileName + writeToFile(filePath,Some(outputFileHeader),descriptionsAsCSV,None) + } + + /** + * creates and collects instances of all output file generating classes + * @return collected class instances + */ + private def getClassesGeneratingOutputs(event : ControlerEvent): List[OutputDataDescriptor] = List( + new ModeChosenAnalysis(new ModeChosenAnalysis.ModeChosenComputation, this.beamServices.beamConfig), + new RealizedModeAnalysis(new RealizedModeAnalysis.RealizedModesStatsComputation), + new RideHailRevenueAnalysis(new RideHailSurgePricingManager(this.beamServices)), + new PersonTravelTimeAnalysis(new PersonTravelTimeAnalysis.PersonTravelTimeComputation), + new FuelUsageAnalysis(new FuelUsageAnalysis.FuelUsageStatsComputation), + new ExpectedMaxUtilityHeatMap( + this.eventsManager, + this.scenario.getNetwork, + event.getServices.getControlerIO, + this.beamServices.beamConfig.beam.outputs.writeEventsInterval + ), + new PhyssimCalcLinkSpeedStats(scenario.getNetwork, event.getServices.getControlerIO, beamServices.beamConfig), + new PhyssimCalcLinkSpeedDistributionStats(scenario.getNetwork, event.getServices.getControlerIO, beamServices.beamConfig), + new RideHailWaitingAnalysis(new RideHailWaitingAnalysis.WaitingStatsComputation, beamServices.beamConfig), + new GraphSurgePricing(new RideHailSurgePricingManager(beamServices)), + new RideHailingWaitingSingleAnalysis(beamServices.beamConfig, new RideHailingWaitingSingleAnalysis.RideHailingWaitingSingleComputation), + new BeamMobsim( + beamServices, + transportNetwork, + scenario, + eventsManager, + actorSystem, + new RideHailSurgePricingManager(beamServices) + ), + StopWatchOutputs, + ScoreStatsOutputs, + SummaryStatsOutputs, + CountsCompareOutputs, + EventOutputs, + LegHistogramOutputs, + RideHailTripDistanceOutputs, + TripDurationOutputs, + BiasErrorGraphDataOutputs, + BiasNormalizedErrorGraphDataOutputs + ) + + /** + * Writes data to the output file at specified path. + * @param filePath path of the output file to write data to + * @param fileHeader an optional header to be appended (if any) + * @param data data to be written to the file + * @param fileFooter an optional footer to be appended (if any) + */ + private def writeToFile(filePath : String,fileHeader : Option[String],data : String,fileFooter : Option[String]): Unit = { + val bw = new BufferedWriter(new FileWriter(filePath)) + try { + if(fileHeader.isDefined) + bw.append(fileHeader.get) + bw.append(data) + if(fileFooter.isDefined) + bw.append(fileFooter.get) + } + catch { + case e: IOException => + e.printStackTrace() + } finally { + bw.close() + } + } + +} + +object ScoreStatsOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename("scorestats.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "ITERATION", "Iteration number")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "avg. EXECUTED", "Average of the total execution time for the given iteration")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "avg. WORST", "Average of worst case time complexities for the given iteration")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "avg. AVG", "Average of average case time complexities for the given iteration")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "avg. BEST", "Average of best case time complexities for the given iteration")) + list + } +} + +object StopWatchOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename("stopwatch.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Iteration", "Iteration number")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN iteration", "Begin time of the iteration")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN iterationStartsListeners", "Time at which the iteration start event listeners started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END iterationStartsListeners", "Time at which the iteration start event listeners ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN replanning", "Time at which the replanning event started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END replanning", "Time at which the replanning event ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN beforeMobsimListeners", "Time at which the beforeMobsim event listeners started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN dump all plans", "Begin dump all plans")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END dump all plans", "End dump all plans")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END beforeMobsimListeners", "Time at which the beforeMobsim event listeners ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN mobsim", "Time at which the mobsim run started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END mobsim", "Time at which the mobsim run ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN afterMobsimListeners", "Time at which the afterMobsim event listeners started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END afterMobsimListeners", "Time at which the afterMobsim event listeners ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN scoring", "Time at which the scoring event started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END scoring", "Time at which the scoring event ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN iterationEndsListeners", "Time at which the iteration ends event listeners ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "BEGIN compare with counts", "Time at which compare with counts started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END compare with counts", "Time at which compare with counts ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "END iteration", "Time at which the iteration ended")) + list + } +} + +object SummaryStatsOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputFilename("summaryStats.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Iteration", "Iteration number")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "agentHoursOnCrowdedTransit", "Time taken by the agent to travel in a crowded transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuelConsumedInMJ_Diesel", "Amount of diesel consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuelConsumedInMJ_Food", "Amount of food consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuelConsumedInMJ_Electricity", "Amount of electricity consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuelConsumedInMJ_Gasoline", "Amount of gasoline consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numberOfVehicles_BEV", "Time at which the beforeMobsim event listeners started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numberOfVehicles_BODY-TYPE-DEFAULT", "Number of vehicles of type BODY-TYPE-DEFAULT")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numberOfVehicles_BUS-DEFAULT", "Number of vehicles of type BUS-DEFAULT")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numberOfVehicles_Car", "Time at which the beforeMobsim event listeners ended")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numberOfVehicles_SUBWAY-DEFAULT", "Time at which the mobsim run started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personTravelTime_car", "Time taken by the passenger to travel by car")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personTravelTime_drive_transit", "Time taken by the passenger to drive to the transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personTravelTime_others", "Time taken by the passenger to travel by other means")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personTravelTime_walk", "Time taken by the passenger to travel on foot")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personTravelTime_walk_transit", "Time taken by the passenger to walk to the transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalCostIncludingSubsidy_walk_transit", "Total cost (including subsidy) paid by the passenger to reach destination by walking to transit and then transit to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalCostIncludingSubsidy_ride_hail", "Total cost (including subsidy) paid by the passenger to reach destination on a ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalSubsidy_drive_transit", "Total subsidy amount paid to passenger to reach destination by driving to transit and then transit to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalSubsidy_ride_hail", "Total subsidy amount paid to passenger to reach destination by ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalSubsidy_walk_transit", "Total subsidy amount paid to passenger to reach destination by walking to transit and then transit to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalTravelTime", "Total time taken by the passenger to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "totalVehicleDelay", "Sum of all the delay times incurred by the vehicle during the travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleHoursTraveled_BEV", "Time taken (in hours) by the vehicle to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleHoursTraveled_BODY-TYPE-DEFAULT", "Time taken (in hours) by the vehicle to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleHoursTraveled_BUS-DEFAULT", "Time taken (in hours) by the vehicle(bus) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleHoursTraveled_Car", "Time taken (in hours) by the vehicle(car) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleHoursTraveled_SUBWAY-DEFAULT", "Time taken (in hours) by the vehicle (subway) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_BEV", "Miles covered by the vehicle to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_BODY-TYPE-DEFAULT", "Miles covered by the vehicle to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_BUS-DEFAULT", "Miles covered by the vehicle(bus) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_Car", "Miles covered by the vehicle(car) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_SUBWAY-DEFAULT", "Miles covered by the vehicle(subway) to travel from source to destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicleMilesTraveled_total", "Miles covered by the vehicles(all modes) to travel from source to destination")) + list + } +} + +object CountsCompareOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"countsCompare.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Link Id", "Iteration number")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Count", "Time taken by the agent to travel in a crowded transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Station Id", "Amount of diesel consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Hour", "Amount of food consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "MATSIM volumes", "Amount of electricity consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Relative Error", "Amount of gasoline consumed in megajoule")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "Normalized Relative Error", "Time at which the beforeMobsim event listeners started")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "GEH", "GEH")) + list + } +} + +object EventOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"events.csv") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "person", "Person(Agent) Id")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicle", "vehicle id")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "time", "Start time of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "type", "Type of the event")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuel", "Type of fuel used in the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "duration", "Duration of the travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "cost", "Cost of travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "location.x", "X co-ordinate of the location")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "location.y", "Y co-ordinate of the location")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "parking_type", "Parking type chosen by the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "pricing_model", "Pricing model")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "charging_type", "Charging type of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "parking_taz", "Parking TAZ")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "distance", "Distance between source and destination")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "location", "Location of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "mode", "Mode of travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "currentTourMode", "Current tour mode")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "expectedMaximumUtility", "Expected maximum utility of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "availableAlternatives", "Available alternatives for travel for the passenger")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "personalVehicleAvailable", "Whether the passenger possesses a personal vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "tourIndex", "Tour index")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "facility", "Facility availed by the passenger")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departTime", "Time of departure of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "originX", "X ordinate of the passenger origin point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "originY", "Y ordinate of the passenger origin point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "destinationX", "X ordinate of the passenger destination point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "destinationY", "Y ordinate of the passenger destination point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "fuelType", "Fuel type of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "num_passengers", "Num of passengers travelling in the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "links", "Number of links in the network")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departure_time", "Departure time of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrival_time", "Arrival time of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vehicle_type", "Type of vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "capacity", "Total capacity of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "start.x", "X ordinate of the start point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "start.y", "Y ordinate of the start point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "end.x", "X ordinate of the vehicle end point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "end.y", "Y ordinate of the vehicle end point")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "end_leg_fuel_level", "Fuel level at the end of the travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "seating_capacity", "Seating capacity of the vehicle")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "costType", "Type of cost of travel incurred on the passenger")) + list + } +} + +object LegHistogramOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"legHistogram.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "time", "Time")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "time", "Time")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_all", "Total number of departures on all modes")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_all", "Total number of arrivals on all modes")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "duration", "Duration of travel")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_all", "Total number of travels that got stuck on all modes")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_all", "Total number of travels by all modes")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_car", "Total number of departures by car")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_car", "Total number of departures by car")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_car", "Total number of travels that got stuck while travelling by car")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_car", "Total number of travels made by car")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_drive_transit", "Total number of departures by drive to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_drive_transit", "Total number of arrivals by drive to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_drive_transit", "Total number of travels that got stuck while travelling by drive to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_drive_transit", "Total number of travels made by drive to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_ride_hail", "Total number of departures by ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_ride_hail", "Total number of arrivals by ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_ride_hail", "Total number of travels that got stuck while travelling by ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_ride_hail", "Total number of travels made by ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_walk", "Total number of departures on foot")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_walk", "Total number of arrivals on foot")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_walk", "Total number of travels that got stuck while travelling on foot")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_walk", "Total number of travels made on foot")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "departures_walk_transit", "Total number of departures by walk to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "arrivals_walk_transit", "Total number of arrivals by walk to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "stuck_walk_transit", "Total number of travels that got stuck while travelling by walk to transit")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "en-route_walk_transit", "Total number of travels made by walk to transit")) + list + } +} + +object RideHailTripDistanceOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"rideHailTripDistance.csv") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "hour", "Hour of the day")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "numPassengers", "Number of passengers travelling in the ride hail")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "vkt", "Total number of kilometers travelled by the ride hail vehicle")) + list + } +} + +object TripDurationOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"tripDuration.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "pattern", "Pattern")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "(5*i)+", "Value")) + list + } +} + +object BiasErrorGraphDataOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"biasErrorGraphData.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "hour", "Hour of the day")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "mean relative error", "Mean relative error")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "mean bias", "Mean bias value")) + list + } +} + +object BiasNormalizedErrorGraphDataOutputs extends OutputDataDescriptor { + /** + * Get description of fields written to the output files. + * + * @return list of data description objects + */ + override def getOutputDataDescriptions: java.util.List[OutputDataDescription] = { + val outputFilePath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(0,"biasNormalizedErrorGraphData.txt") + val outputDirPath = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getOutputPath + val relativePath = outputFilePath.replace(outputDirPath, "") + val list = new java.util.ArrayList[OutputDataDescription] + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "hour", "Hour of the day")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "mean normalized relative error", "Mean normalized relative error")) + list.add(OutputDataDescription(this.getClass.getSimpleName.dropRight(1), relativePath, "mean bias", "Mean bias value")) + list + } +} diff --git a/src/main/scala/beam/sim/BeamSim.scala b/src/main/scala/beam/sim/BeamSim.scala index de134656286..e4d4e542a50 100755 --- a/src/main/scala/beam/sim/BeamSim.scala +++ b/src/main/scala/beam/sim/BeamSim.scala @@ -46,6 +46,7 @@ class BeamSim @Inject()( private val beamServices: BeamServices, private val eventsManager: EventsManager, private val scenario: Scenario, + private val beamOutputDataDescriptionGenerator: BeamOutputDataDescriptionGenerator, ) extends StartupListener with IterationEndsListener with ShutdownListener @@ -207,6 +208,7 @@ class BeamSim @Inject()( logger.info("Generating html page to compare graphs (across all iterations)") BeamGraphComparator.generateGraphComparisonHtmlPage(event, firstIteration, lastIteration) + beamOutputDataDescriptionGenerator.generateDescriptors(event) Await.result(actorSystem.terminate(), Duration.Inf) logger.info("Actor system shut down") diff --git a/src/main/scala/beam/sim/OutputDataDescription.scala b/src/main/scala/beam/sim/OutputDataDescription.scala new file mode 100644 index 00000000000..ec41115aa76 --- /dev/null +++ b/src/main/scala/beam/sim/OutputDataDescription.scala @@ -0,0 +1,13 @@ +package beam.sim + +/** + * A class that describes the fields in every output file. + * @param className name of the class that generates it + * @param outputFile relative path of the file in the output folder + * @param field field to be described + * @param description description of the field + */ +case class OutputDataDescription(className : String, + outputFile:String, + field:String, + description:String)