From 975a5c7944fbdd14779acc60aecef0aec2de3110 Mon Sep 17 00:00:00 2001 From: rajnikant Date: Wed, 31 Oct 2018 04:38:34 +0530 Subject: [PATCH 1/4] add beam-utility project --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 0d0ec8ba472..b1afb0acccc 100755 --- a/build.gradle +++ b/build.gradle @@ -97,6 +97,9 @@ allprojects { } dependencies { + // beam-utility + compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: 'master' + //////////////////////////// // Java dependencies From 6488dcd8511dbebaee75917d0ee4dde80a03afd3 Mon Sep 17 00:00:00 2001 From: rajnikant Date: Thu, 1 Nov 2018 19:48:04 +0530 Subject: [PATCH 2/4] insert beam-utilities dependency, split personVehicleTransitionStats, remove jai_codec,jai_imageio --- build.gradle | 21 ++- .../plots/PersonVehicleTransitionStats.java | 125 ++---------------- 2 files changed, 32 insertions(+), 114 deletions(-) diff --git a/build.gradle b/build.gradle index b1afb0acccc..6dd240743e9 100755 --- a/build.gradle +++ b/build.gradle @@ -97,9 +97,9 @@ allprojects { } dependencies { - // beam-utility - compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: 'master' + //beam-utilities + compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: 'master-SNAPSHOT' //////////////////////////// // Java dependencies @@ -139,6 +139,7 @@ dependencies { // GPLv3 compile group: 'org.matsim.contrib', name: 'multimodal', version: '0.10.0' compile group: 'org.matsim.contrib', name: 'bicycle', version: '0.10.0' + compile (group: 'org.matsim.contrib', name: 'decongestion', version: '0.11.0-2018w44'){ exclude group: 'org.matsim', module: 'matsim' } @@ -247,6 +248,22 @@ scalafmt { // configFilePath = ".scalafmt.conf" // .scalafmt.conf in the project root is default value, provide only if other location is needed } + + +configurations.all { + resolutionStrategy { + eachDependency { DependencyResolveDetails dependencyResolveDetails -> + final requestedDependency = dependencyResolveDetails.requested + if (requestedDependency.name != 'beam-utilities') { + force 'javax.media:jai_core:1.1.3' + } + } + } + exclude group: 'javax.media', module: 'jai_codec' + exclude group: 'javax.media', module: 'jai_imageio' + +} + //compileScala.dependsOn(scalafmtAll) // Task to run scala tests, as Scala tests not picked up by Gradle by default. diff --git a/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java b/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java index dceff022c9e..b0e305da70b 100755 --- a/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java +++ b/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java @@ -1,33 +1,20 @@ package beam.analysis.plots; +import beam.analysis.plot.PlotGraph; import beam.sim.config.BeamConfig; import beam.sim.metrics.MetricsSupport; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartUtilities; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.CategoryAxis; -import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.plot.XYPlot; -import org.jfree.data.xy.XYSeries; -import org.jfree.data.xy.XYSeriesCollection; import org.matsim.api.core.v01.events.Event; import org.matsim.api.core.v01.events.PersonEntersVehicleEvent; import org.matsim.api.core.v01.events.PersonLeavesVehicleEvent; import org.matsim.core.controler.events.IterationEndsEvent; -import org.matsim.core.utils.io.UncheckedIOException; import org.matsim.core.utils.misc.Time; -import java.awt.*; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; import java.util.*; import java.util.List; public class PersonVehicleTransitionStats implements BeamStats, MetricsSupport { - private static final List vehicleType = new ArrayList<>(Arrays.asList("body", "rideHail" , "others")); + private static final List vehicleType = new ArrayList<>(Arrays.asList("body", "rideHail", "others")); private static Map> personEnterCount = new HashMap<>(); private static Map> personExitCount = new HashMap<>(); @@ -35,10 +22,11 @@ public class PersonVehicleTransitionStats implements BeamStats, MetricsSupport { private static Map modePerson = new HashMap<>(); private static final String fileName = "tripHistogram"; private static final String xAxisLabel = "time (binSize= sec)"; + public PlotGraph plotGraph = new PlotGraph(); private int binSize; private int numOfBins; - public PersonVehicleTransitionStats(BeamConfig beamConfig){ + public PersonVehicleTransitionStats(BeamConfig beamConfig) { binSize = beamConfig.beam().outputs().stats().binSize(); String endTime = beamConfig.matsim().modules().qsim().endTime(); Double _endTime = Time.parseTime(endTime); @@ -69,12 +57,13 @@ public void createGraph(IterationEndsEvent event) { if (personEnterCount.size() == 0 && personExitCount.size() == 0) { continue; } - writeGraphic(event.getIteration(), mode); + plotGraph.writeGraphic(GraphsStatsAgentSimEventsListener.CONTROLLER_IO, event.getIteration(), mode, fileName, personEnterCount, personExitCount, onRoutes, xAxisLabel, binSize); + } } private void processPersonVehicleTransition(Event event) { - int index = getBinIndex(event.getTime()); + int index = plotGraph.getBinIndex(event.getTime(), this.binSize, this.numOfBins); if (PersonEntersVehicleEvent.EVENT_TYPE.equals(event.getEventType())) { String personId = event.getAttributes().get(PersonEntersVehicleEvent.ATTRIBUTE_PERSON); @@ -91,11 +80,10 @@ private void processPersonVehicleTransition(Event event) { } String unitVehicle; - boolean isDigit = vehicleId.replace("-","").chars().allMatch( Character::isDigit ); - if(isDigit){ + boolean isDigit = vehicleId.replace("-", "").chars().allMatch(Character::isDigit); + if (isDigit) { unitVehicle = "car"; - } - else { + } else { unitVehicle = vehicleType.stream().filter(vehicleId::contains).findAny().orElse("others"); } @@ -143,11 +131,10 @@ private void processPersonVehicleTransition(Event event) { } String unitVehicle; - boolean isDigit = vehicleId.replace("-","").chars().allMatch( Character::isDigit ); - if(isDigit){ + boolean isDigit = vehicleId.replace("-", "").chars().allMatch(Character::isDigit); + if (isDigit) { unitVehicle = "car"; - } - else { + } else { unitVehicle = vehicleType.stream().filter(vehicleId::contains).findAny().orElse("others"); } @@ -183,90 +170,4 @@ private void processPersonVehicleTransition(Event event) { } - private JFreeChart getGraphic(String mode, int iteration) { - - final XYSeriesCollection xyData = new XYSeriesCollection(); - final XYSeries enterSeries = new XYSeries("Enter", false, true); - final XYSeries exitSeries = new XYSeries("Leave", false, true); - final XYSeries onRouteSeries = new XYSeries("en route", false, true); - - Map personEnter = personEnterCount.get(mode); - if (personEnter != null && personEnter.size() > 0) { - Set enterKeys = personEnter.keySet(); - for (Integer key : enterKeys) { - enterSeries.add(key, personEnter.get(key)); - } - } - - - Map personExit = personExitCount.get(mode); - if (personExit != null && personExit.size() > 0) { - Set exitKeys = personExit.keySet(); - for (Integer key : exitKeys) { - exitSeries.add(key, personExit.get(key)); - } - } - - - Map indexCount = onRoutes.get(mode); - if (indexCount != null && indexCount.size() > 0) { - Set indexKeys = indexCount.keySet(); - for (Integer key : indexKeys) { - onRouteSeries.add(key, indexCount.get(key)); - } - } - - xyData.addSeries(enterSeries); - xyData.addSeries(exitSeries); - xyData.addSeries(onRouteSeries); - - final JFreeChart chart = ChartFactory.createXYLineChart( - "Trip Histogram, " + mode + ", it." + iteration, - xAxisLabel.replace("", String.valueOf(binSize)), "# persons", - xyData, - PlotOrientation.VERTICAL, - true, // legend - false, // tooltips - false // urls - ); - - - XYPlot plot = chart.getXYPlot(); - plot.getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - final CategoryAxis axis1 = new CategoryAxis("sec"); - axis1.setTickLabelFont(new Font("SansSerif", Font.PLAIN, 7)); - plot.setDomainAxis(new NumberAxis(xAxisLabel.replace("",String.valueOf(binSize)))); - - plot.getRenderer().setSeriesStroke(0, new BasicStroke(2.0f)); - plot.getRenderer().setSeriesStroke(1, new BasicStroke(2.0f)); - plot.getRenderer().setSeriesStroke(2, new BasicStroke(2.0f)); - plot.setBackgroundPaint(Color.white); - plot.setRangeGridlinePaint(Color.gray); - plot.setDomainGridlinePaint(Color.gray); - - return chart; - } - - private void writeGraphic(Integer iteration, String mode) { - try { - - String filename = fileName + "_" + mode + ".png"; - String path = GraphsStatsAgentSimEventsListener.CONTROLLER_IO.getIterationFilename(iteration, filename); - int index = path.lastIndexOf("/"); - File outDir = new File(path.substring(0, index) + "/tripHistogram"); - if (!outDir.isDirectory()) Files.createDirectories(outDir.toPath()); - String newPath = outDir.getPath() + path.substring(index); - ChartUtilities.saveChartAsPNG(new File(newPath), getGraphic(mode, iteration), 1024, 768); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private int getBinIndex(final double time) { - int bin = (int) (time / this.binSize); - if (bin >= this.numOfBins) { - return this.numOfBins; - } - return bin; - } } \ No newline at end of file From fd3c9bb9eb97b9b68bca79b9ed83dd84f9a43a89 Mon Sep 17 00:00:00 2001 From: rajnikant Date: Thu, 1 Nov 2018 20:59:59 +0530 Subject: [PATCH 3/4] just added a line to start build again --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 6dd240743e9..aa30c13fa62 100755 --- a/build.gradle +++ b/build.gradle @@ -98,6 +98,7 @@ allprojects { dependencies { + //beam-utilities compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: 'master-SNAPSHOT' From aac7b8f7362848b5a226b4887748eb733abe34f2 Mon Sep 17 00:00:00 2001 From: rajnikant Date: Tue, 6 Nov 2018 00:34:19 +0530 Subject: [PATCH 4/4] move classes from beam to beam-utility --- build.gradle | 4 +- .../plots/PersonVehicleTransitionStats.java | 2 +- .../via/EventWriterXML_viaCompatible.java | 190 -------------- src/main/java/beam/router/r5/OsmToMATSim.java | 245 ----------------- .../java/beam/utils/BeamCalcLinkStats.java | 246 ------------------ src/main/scala/beam/utils/SpatialPlot.scala | 239 +---------------- 6 files changed, 5 insertions(+), 921 deletions(-) delete mode 100755 src/main/java/beam/analysis/via/EventWriterXML_viaCompatible.java delete mode 100755 src/main/java/beam/router/r5/OsmToMATSim.java delete mode 100755 src/main/java/beam/utils/BeamCalcLinkStats.java diff --git a/build.gradle b/build.gradle index aa30c13fa62..5b30ff899d1 100755 --- a/build.gradle +++ b/build.gradle @@ -100,12 +100,10 @@ dependencies { //beam-utilities - compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: 'master-SNAPSHOT' - + compile group: 'com.github.LBNL-UCB-STI', name: 'beam-utilities', version: '-SNAPSHOT' //////////////////////////// // Java dependencies //////////////////////////// - compile group: 'com.google.inject', name: 'guice', version: '4.1.0' compile group: 'com.google.inject.extensions', name: 'guice-assistedinject', version: '4.1.0' compile group: 'com.google.inject.extensions', name: 'guice-multibindings', version: '4.1.0' diff --git a/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java b/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java index b0e305da70b..66b4b110dd9 100755 --- a/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java +++ b/src/main/java/beam/analysis/plots/PersonVehicleTransitionStats.java @@ -22,7 +22,7 @@ public class PersonVehicleTransitionStats implements BeamStats, MetricsSupport { private static Map modePerson = new HashMap<>(); private static final String fileName = "tripHistogram"; private static final String xAxisLabel = "time (binSize= sec)"; - public PlotGraph plotGraph = new PlotGraph(); + private PlotGraph plotGraph = new PlotGraph(); private int binSize; private int numOfBins; diff --git a/src/main/java/beam/analysis/via/EventWriterXML_viaCompatible.java b/src/main/java/beam/analysis/via/EventWriterXML_viaCompatible.java deleted file mode 100755 index ee05db8910d..00000000000 --- a/src/main/java/beam/analysis/via/EventWriterXML_viaCompatible.java +++ /dev/null @@ -1,190 +0,0 @@ -package beam.analysis.via; - - -import beam.utils.DebugLib; -import org.matsim.api.core.v01.events.Event; -import org.matsim.core.events.algorithms.EventWriter; -import org.matsim.core.events.handler.BasicEventHandler; -import org.matsim.core.utils.io.IOUtils; -import org.matsim.core.utils.io.UncheckedIOException; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; - -// for some reason via is expecting wait2link event, instead of vehicle enters traffic event (dec. 2017) -// perhaps also has to do with the fact, that we are not using most uptodate matsim version -// this class can be replaced by default EventWriterXML, as this issue gets resolved. - -public class EventWriterXML_viaCompatible implements EventWriter, BasicEventHandler { - private static final String TNC = "ride"; - private static final String BUS = "SF"; - private static final String CAR = "car"; - private final BufferedWriter out; - private boolean eventsForFullVersionOfVia; - HashMap> filterPeopleForViaDemo = new HashMap<>(); - HashMap maxPeopleForViaDemo = new HashMap<>(); - - public EventWriterXML_viaCompatible(final String outFileName, boolean eventsForFullVersionOfVia) { - this.out = IOUtils.getBufferedWriter(outFileName); - this.eventsForFullVersionOfVia = eventsForFullVersionOfVia; - - filterPeopleForViaDemo.put(CAR, new HashSet<>()); - filterPeopleForViaDemo.put(BUS, new HashSet<>()); - filterPeopleForViaDemo.put(TNC, new HashSet<>()); - - maxPeopleForViaDemo.put(CAR, 420); - maxPeopleForViaDemo.put(BUS, 50); - maxPeopleForViaDemo.put(TNC, 30); - - try { - this.out.write("\n\n"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - - @Override - public void closeFile() { - try { - this.out.write(""); - // I added a "\n" to make it look nicer on the console. Can't say if this may have unintended side - // effects anywhere else. kai, oct'12 - // fails signalsystems test (and presumably other tests in contrib/playground) since they compare - // checksums of event files. Removed that change again. kai, oct'12 - this.out.close(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Deprecated - public void init(final String outfilename) { - throw new RuntimeException("Please create a new instance."); - } - - @Override - public void reset(final int iter) { - } - - private boolean addPersonToEventsFile(String person) { - - if (eventsForFullVersionOfVia){ - return true; - } - - String personLabel; - - if (person.contains(BUS)) { - personLabel = BUS; - } else if (person.contains(TNC)) { - personLabel = TNC; - } else { - personLabel = CAR; - } - - if (filterPeopleForViaDemo.get(personLabel).size() < maxPeopleForViaDemo.get(personLabel) || filterPeopleForViaDemo.get(personLabel).contains(person)) { - filterPeopleForViaDemo.get(personLabel).add(person); - return true; - } else { - return false; - } - } - - @Override - public void handleEvent(final Event event) { - - // select 500 agents for sf-light demo in via - //if (outFileName.contains("sf-light")){ - Map eventAttributes = event.getAttributes(); - String person = eventAttributes.get("person"); - String vehicle = eventAttributes.get("vehicle"); - - if (person != null) { - if (!addPersonToEventsFile(person)) return; - } else { - if (!addPersonToEventsFile(vehicle)) return; - } - //} - - try { - this.out.append("\t entry : eventAttributes.entrySet()) { - this.out.append(entry.getKey()); - this.out.append("=\""); - this.out.append(encodeAttributeValue(entry.getValue())); - this.out.append("\" "); - } - this.out.append(" />\n"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - // the following method was taken from MatsimXmlWriter in order to correctly encode attributes, but - // to forego the overhead of using the full MatsimXmlWriter. - - /** - * Encodes the given string in such a way that it no longer contains - * characters that have a special meaning in xml. - * - * @param attributeValue - * @return String with some characters replaced by their xml-encoding. - * @see http://www.w3.org/International/questions/qa-escapes#use - */ - private String encodeAttributeValue(final String attributeValue) { - if (attributeValue == null) { - return null; - } - int len = attributeValue.length(); - boolean encode = false; - for (int pos = 0; pos < len; pos++) { - char ch = attributeValue.charAt(pos); - if (ch == '<') { - encode = true; - break; - } else if (ch == '>') { - encode = true; - break; - } else if (ch == '\"') { - encode = true; - break; - } else if (ch == '&') { - encode = true; - break; - } - } - if (encode) { - StringBuilder bf = new StringBuilder(); - for (int pos = 0; pos < len; pos++) { - char ch = attributeValue.charAt(pos); - if (ch == '<') { - bf.append("<"); - } else if (ch == '>') { - bf.append(">"); - } else if (ch == '\"') { - bf.append("""); - } else if (ch == '&') { - bf.append("&"); - } else { - bf.append(ch); - } - } - - return bf.toString(); - } - return attributeValue; - - } - -} - diff --git a/src/main/java/beam/router/r5/OsmToMATSim.java b/src/main/java/beam/router/r5/OsmToMATSim.java deleted file mode 100755 index 3ecf0e0ac03..00000000000 --- a/src/main/java/beam/router/r5/OsmToMATSim.java +++ /dev/null @@ -1,245 +0,0 @@ -package beam.router.r5; - -import com.conveyal.osmlib.Way; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.network.Node; -import org.matsim.core.network.NetworkUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Created by Andrew A. Campbell on 7/25/17. - * This class is based off of MATSim's OsmNetworkReader. Particularly, it is used to generate all the link - * attributes in the MATSim network based on the OSM way's tags the same way OsmNetworkReader does. - */ - -public class OsmToMATSim { - - private final static Logger log = LoggerFactory.getLogger(OsmToMATSim.class); - - private final static String TAG_LANES = "lanes"; - private final static String TAG_HIGHWAY = "highway"; - private final static String TAG_MAXSPEED = "maxspeed"; - private final static String TAG_JUNCTION = "junction"; - private final static String TAG_ONEWAY = "oneway"; - private final static String TAG_ACCESS = "access"; - private final static String[] ALL_TAGS = new String[]{TAG_LANES, TAG_HIGHWAY, TAG_MAXSPEED, TAG_JUNCTION, TAG_ONEWAY, TAG_ACCESS}; - public final Map highwayDefaults = new HashMap<>(); - private final Set unknownHighways = new HashSet<>(); // Used for logging in OsmNetworkReader - private final Set unknownMaxspeedTags = new HashSet<>(); - private final Set unknownLanesTags = new HashSet<>(); - private final Network mNetwork; - private long id = 0; - - - public OsmToMATSim(final Network mNetwork, boolean useBEAMHighwayDefaults) { - this.mNetwork = mNetwork; - if (useBEAMHighwayDefaults) { - - log.info("Falling back to default values."); - this.setBEAMHighwayDefaults(1, "motorway", 2, 120.0 / 3.6, 1.0, 2000, true); - this.setBEAMHighwayDefaults(1, "motorway_link", 1, 80.0 / 3.6, 1.0, 1500, true); - this.setBEAMHighwayDefaults(2, "trunk", 1, 80.0 / 3.6, 1.0, 2000); - this.setBEAMHighwayDefaults(2, "trunk_link", 1, 50.0 / 3.6, 1.0, 1500); - this.setBEAMHighwayDefaults(3, "primary", 1, 80.0 / 3.6, 1.0, 1500); - this.setBEAMHighwayDefaults(3, "primary_link", 1, 60.0 / 3.6, 1.0, 1500); - -// this.setBEAMHighwayDefaults(4, "secondary", 1, 60.0/3.6, 1.0, 1000); -// this.setBEAMHighwayDefaults(5, "tertiary", 1, 45.0/3.6, 1.0, 600); -// this.setBEAMHighwayDefaults(6, "minor", 1, 45.0/3.6, 1.0, 600); -// this.setBEAMHighwayDefaults(6, "unclassified", 1, 45.0/3.6, 1.0, 600); -// this.setBEAMHighwayDefaults(6, "residential", 1, 30.0/3.6, 1.0, 600); -// this.setBEAMHighwayDefaults(6, "living_street", 1, 15.0/3.6, 1.0, 300); - - // Setting the following to considerably smaller values, since there are often traffic signals/non-prio intersections. - // If someone does a systematic study, please report. kai, jul'16 - this.setBEAMHighwayDefaults(4, "secondary", 1, 30.0 / 3.6, 1.0, 1000); - this.setBEAMHighwayDefaults(4, "secondary_link", 1, 30.0 / 3.6, 1.0, 1000); - this.setBEAMHighwayDefaults(5, "tertiary", 1, 25.0 / 3.6, 1.0, 600); - this.setBEAMHighwayDefaults(5, "tertiary_link", 1, 25.0 / 3.6, 1.0, 600); - this.setBEAMHighwayDefaults(6, "minor", 1, 20.0 / 3.6, 1.0, 600); - this.setBEAMHighwayDefaults(6, "residential", 1, 15.0 / 3.6, 1.0, 600); - this.setBEAMHighwayDefaults(6, "living_street", 1, 10.0 / 3.6, 1.0, 300); - // changing the speed values failed the evacuation ScenarioGenerator test because of a different network -- DESPITE - // the fact that all the speed values are reset to some other value there. No idea what happens there. kai, jul'16 - - this.setBEAMHighwayDefaults(6, "unclassified", 1, 45.0 / 3.6, 1.0, 600); - } - } - - /** - * Replaces OsmNetworkReader.setHighwayDefaults - * Sets defaults for converting OSM highway paths into MATSim links, assuming it is no oneway road. - * - * @param hierarchy The hierarchy layer the highway appears. - * @param highwayType The type of highway these defaults are for. - * @param lanesPerDirection number of lanes on that road type in each direction - * @param freespeed the free speed vehicles can drive on that road type [meters/second] - * @param freespeedFactor the factor the freespeed is scaled - * @param laneCapacity_vehPerHour the capacity per lane [veh/h] - * @see http://wiki.openstreetmap.org/wiki/Map_Features#Highway - */ - public void setBEAMHighwayDefaults(final int hierarchy, final String highwayType, final double lanesPerDirection, final double freespeed, final double freespeedFactor, final double laneCapacity_vehPerHour) { - setBEAMHighwayDefaults(hierarchy, highwayType, lanesPerDirection, freespeed, freespeedFactor, laneCapacity_vehPerHour, false); - } - - /** - * Replaces OsmNetworkReader.setHighwayDefaults - * Sets defaults for converting OSM highway paths into MATSim links. - * - * @param hierarchy The hierarchy layer the highway appears in. - * @param highwayType The type of highway these defaults are for. - * @param lanesPerDirection number of lanes on that road type in each direction - * @param freespeed the free speed vehicles can drive on that road type [meters/second] - * @param freespeedFactor the factor the freespeed is scaled - * @param laneCapacity_vehPerHour the capacity per lane [veh/h] - * @param oneway true to say that this road is a oneway road - */ - public void setBEAMHighwayDefaults(final int hierarchy, final String highwayType, final double lanesPerDirection, final double freespeed, - final double freespeedFactor, final double laneCapacity_vehPerHour, final boolean oneway) { - this.highwayDefaults.put(highwayType, new BEAMHighwayDefaults(hierarchy, lanesPerDirection, freespeed, freespeedFactor, laneCapacity_vehPerHour, oneway)); - } - - public Link createLink(final Way way, long osmID, Integer r5ID, final Node fromMNode, final Node toMNode, - final double length, HashSet flagStrings) { - String highway = way.getTag(TAG_HIGHWAY); - if (highway == null) { - highway = "unclassified"; - } - BEAMHighwayDefaults defaults = this.highwayDefaults.get(highway); - - if (defaults == null) { - defaults = this.highwayDefaults.get("unclassified"); - } - - double nofLanes = defaults.lanesPerDirection; - double laneCapacity = defaults.laneCapacity; - double freespeed = defaults.freespeed; - double freespeedFactor = defaults.freespeedFactor; - boolean oneway = defaults.oneway; - boolean onewayReverse = false; - - // check if there are tags that overwrite defaults - // - check tag "junction" - if ("roundabout".equals(way.getTag(TAG_JUNCTION))) { - // if "junction" is not set in tags, get() returns null and equals() evaluates to false - oneway = true; - } - - // check tag "oneway" - String onewayTag = way.getTag(TAG_ONEWAY); - if (onewayTag != null) { - if ("yes".equals(onewayTag)) { - oneway = true; - } else if ("true".equals(onewayTag)) { - oneway = true; - } else if ("1".equals(onewayTag)) { - oneway = true; - } else if ("-1".equals(onewayTag)) { - onewayReverse = true; - oneway = false; - } else if ("no".equals(onewayTag)) { - oneway = false; // may be used to overwrite defaults - } else { - log.warn("Could not interpret oneway tag:" + onewayTag + ". Ignoring it."); - } - } - - // In case trunks, primary and secondary roads are marked as oneway, - // the default number of lanes should be two instead of one. - if (highway.equalsIgnoreCase("trunk") || highway.equalsIgnoreCase("primary") || highway.equalsIgnoreCase("secondary")) { - if ((oneway || onewayReverse) && nofLanes == 1.0) { - nofLanes = 2.0; - } - } - - String maxspeedTag = way.getTag(TAG_MAXSPEED); - if (maxspeedTag != null) { - try { - freespeed = Double.parseDouble(maxspeedTag) / 3.6; // convert km/h to m/s - } catch (NumberFormatException e) { - if (!this.unknownMaxspeedTags.contains(maxspeedTag)) { - this.unknownMaxspeedTags.add(maxspeedTag); - log.warn("Could not parse maxspeed tag:" + e.getMessage() + ". Ignoring it."); - } - } - } - - // check tag "lanes" - String lanesTag = way.getTag(TAG_LANES); - if (lanesTag != null) { - try { - double totalNofLanes = Double.parseDouble(lanesTag); - if (totalNofLanes > 0) { - nofLanes = totalNofLanes; - - //By default, the OSM lanes tag specifies the total number of lanes in both directions. - //So if the road is not oneway (onewayReverse), let's distribute them between both directions - //michalm, jan'16 - if (!oneway && !onewayReverse) { - nofLanes /= 2.; - } - } - } catch (Exception e) { - if (!this.unknownLanesTags.contains(lanesTag)) { - this.unknownLanesTags.add(lanesTag); - log.warn("Could not parse lanes tag:" + e.getMessage() + ". Ignoring it."); - } - } - } - - // create the link(s) - double capacity = nofLanes * laneCapacity; - - boolean scaleMaxSpeed = false; - if (scaleMaxSpeed) { - freespeed = freespeed * freespeedFactor; - } - - // only create link, if both nodes were found, node could be null, since nodes outside a layer were dropped - Id fromId = fromMNode.getId(); - Id toId = toMNode.getId(); - if (this.mNetwork.getNodes().get(fromId) != null && this.mNetwork.getNodes().get(toId) != null) { - Link l = this.mNetwork.getFactory().createLink(Id.create(r5ID, Link.class), this.mNetwork.getNodes().get(fromId), this.mNetwork.getNodes().get(toId)); - l.setLength(length); - l.setFreespeed(freespeed); - l.setCapacity(capacity); - l.setNumberOfLanes(nofLanes); - l.setAllowedModes(flagStrings); - NetworkUtils.setOrigId(l, Long.toString(osmID)); - NetworkUtils.setType(l, highway); - return l; - } else { - throw new RuntimeException(); - } - } - - /** - * Takes the place of the private class OsmNetworkReader.OsmHighwayDefaults - */ - public static class BEAMHighwayDefaults { - public final int hierarchy; - public final double lanesPerDirection; - public final double freespeed; - public final double freespeedFactor; - public final double laneCapacity; - public final boolean oneway; - - public BEAMHighwayDefaults(final int hierarchy, final double lanesPerDirection, final double freespeed, - final double freespeedFactor, final double laneCapacity, final boolean oneway) { - this.hierarchy = hierarchy; - this.lanesPerDirection = lanesPerDirection; - this.freespeed = freespeed; - this.freespeedFactor = freespeedFactor; - this.laneCapacity = laneCapacity; - this.oneway = oneway; - } - } -} diff --git a/src/main/java/beam/utils/BeamCalcLinkStats.java b/src/main/java/beam/utils/BeamCalcLinkStats.java deleted file mode 100755 index b00475c6a91..00000000000 --- a/src/main/java/beam/utils/BeamCalcLinkStats.java +++ /dev/null @@ -1,246 +0,0 @@ -/* *********************************************************************** * - * project: org.matsim.* - * CalcLinkStats.java - * * - * *********************************************************************** * - * * - * copyright : (C) 2007 by the members listed in the COPYING, * - * LICENSE and WARRANTY file. * - * email : info at matsim dot org * - * * - * *********************************************************************** * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * See also COPYING, LICENSE and WARRANTY file * - * * - * *********************************************************************** */ -package beam.utils; - - -import org.matsim.analysis.CalcLinkStats; -import org.matsim.analysis.VolumesAnalyzer; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.network.Link; -import org.matsim.api.core.v01.network.Network; -import org.matsim.core.config.groups.TravelTimeCalculatorConfigGroup; -import org.matsim.core.router.util.TravelTime; -import org.matsim.core.utils.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class BeamCalcLinkStats { - - private final static Logger log = LoggerFactory.getLogger(CalcLinkStats.class); - private static final int MIN = 0; - private static final int MAX = 1; - private static final int SUM = 2; - private static final String[] statType = {"MIN", "MAX", "AVG"}; - private static final int NOF_STATS = 3; - private final Map, LinkData> linkData; - private final int nofHours; - private final Network network; - private int count = 0; - - @Inject - public BeamCalcLinkStats(final Network network, final TravelTimeCalculatorConfigGroup ttConfigGroup) { - this.network = network; - this.linkData = new ConcurrentHashMap<>(); - this.nofHours = (int)TimeUnit.SECONDS.toHours(ttConfigGroup.getMaxTime()); - reset(); - } - - public void addData(final VolumesAnalyzer analyzer, final TravelTime ttimes) { - this.count++; - // TODO verify ttimes has hourly timeBin-Settings - - // go through all links - for (Id linkId : this.linkData.keySet()) { - - // retrieve link from link ID - Link link = this.network.getLinks().get(linkId); - - // get the volumes for the link ID from the analyzier - double[] volumes = analyzer.getVolumesPerHourForLink(linkId); - - // get the destination container for the data from link data (could have gotten this through iterator right away) - LinkData data = this.linkData.get(linkId); - - // prepare the sum variables (for volumes); - long sumVolumes = 0; // daily (0-24) sum - - // go through all hours: - for (int hour = 0; hour < this.nofHours; hour++) { - - // get travel time for hour - double ttime = ttimes.getLinkTravelTime(link, hour * 3600, null, null); - - // add for daily sum: - sumVolumes += volumes[hour]; - - // the following has something to do with the fact that we are doing this for multiple iterations. So there are variations. - // this collects min and max. There is, however, no good control over how many iterations this is collected. - if (this.count == 1) { - data.volumes[MIN][hour] = volumes[hour]; - data.volumes[MAX][hour] = volumes[hour]; - data.ttimes[MIN][hour] = ttime; - data.ttimes[MAX][hour] = ttime; - } else { - if (volumes[hour] < data.volumes[MIN][hour]) data.volumes[MIN][hour] = volumes[hour]; - if (volumes[hour] > data.volumes[MAX][hour]) data.volumes[MAX][hour] = volumes[hour]; - if (ttime < data.ttimes[MIN][hour]) data.ttimes[MIN][hour] = ttime; - if (ttime > data.ttimes[MAX][hour]) data.ttimes[MAX][hour] = ttime; - } - - // this is the regular summing up for each hour - data.volumes[SUM][hour] += volumes[hour]; - data.ttimes[SUM][hour] += volumes[hour] * ttime; - } - // dataVolumes[.][nofHours] are daily (0-24) values - if (this.count == 1) { - data.volumes[MIN][this.nofHours] = sumVolumes; - data.volumes[SUM][this.nofHours] = sumVolumes; - data.volumes[MAX][this.nofHours] = sumVolumes; - } else { - if (sumVolumes < data.volumes[MIN][this.nofHours]) data.volumes[MIN][this.nofHours] = sumVolumes; - data.volumes[SUM][this.nofHours] += sumVolumes; - if (sumVolumes > data.volumes[MAX][this.nofHours]) data.volumes[MAX][this.nofHours] = sumVolumes; - } - } - } - - public void reset() { - this.linkData.clear(); - this.count = 0; - log.info(" resetting `count' to zero. This info is here since we want to check when this" + - " is happening during normal simulation runs. kai, jan'11"); - - // initialize our data-table - for (Link link : this.network.getLinks().values()) { - LinkData data = new LinkData(new double[NOF_STATS][this.nofHours + 1], new double[NOF_STATS][this.nofHours]); - this.linkData.put(link.getId(), data); - } - - } - - public void writeFile(final String filename) { - BufferedWriter out = null; - try { - out = IOUtils.getBufferedWriter(filename); - - // write header - out.write("link,from,to,hour,length,freespeed,capacity,stat,volume,traveltime"); - - out.write("\n"); - - // write data - for (Map.Entry, LinkData> entry : this.linkData.entrySet()) { - - for (int i = 0; i <= this.nofHours; i++) { - for (int j = MIN; j <= SUM; j++) { - Id linkId = entry.getKey(); - LinkData data = entry.getValue(); - Link link = this.network.getLinks().get(linkId); - - out.write(linkId.toString()); - writeCommaAndStr(out, link.getFromNode().getId().toString()); - - writeCommaAndStr(out, link.getToNode().getId().toString()); - - //WRITE HOUR - if (i < this.nofHours) { - writeCommaAndStr(out, Double.toString(i)); - } else { - out.write(","); - out.write( Double.toString(0)); - out.write(" - "); - out.write(Double.toString(this.nofHours)); - } - - writeCommaAndStr(out, Double.toString(link.getLength())); - - writeCommaAndStr(out, Double.toString(link.getFreespeed())); - - writeCommaAndStr(out, Double.toString(link.getCapacity())); - - //WRITE STAT_TYPE - writeCommaAndStr(out, statType[j]); - - //WRITE VOLUME - if (j == SUM) { - writeCommaAndStr(out, Double.toString((data.volumes[j][i]) / this.count)); - } else { - writeCommaAndStr(out, Double.toString(data.volumes[j][i])); - } - - //WRITE TRAVELTIME - - if (j == MIN && i < this.nofHours) { - String ttimesMin = Double.toString(data.ttimes[MIN][i]); - writeCommaAndStr(out, ttimesMin); - - } else if (j == SUM && i < this.nofHours) { - String ttimesMin = Double.toString(data.ttimes[MIN][i]); - if (data.volumes[SUM][i] == 0) { - // nobody traveled along the link in this hour, so we cannot calculate an average - // use the value available or the minimum instead (min and max should be the same, =freespeed) - double ttsum = data.ttimes[SUM][i]; - if (ttsum != 0.0) { - writeCommaAndStr(out, Double.toString(ttsum)); - } else { - writeCommaAndStr(out, ttimesMin); - } - } else { - double ttsum = data.ttimes[SUM][i]; - if (ttsum == 0) { - writeCommaAndStr(out, ttimesMin); - } else { - writeCommaAndStr(out, Double.toString(ttsum / data.volumes[SUM][i])); - } - } - } else if (j == MAX && i < this.nofHours) { - writeCommaAndStr(out, Double.toString(data.ttimes[MAX][i])); - } - - out.write("\n"); - } - } - } - - out.flush(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - log.warn("Could not close output-stream.", e); - } - } - } - } - private void writeCommaAndStr(BufferedWriter out, String str) throws IOException{ - out.write(','); - out.write(str); - } - - private static class LinkData { - final double[][] volumes; - final double[][] ttimes; - - LinkData(final double[][] linksVolumes, final double[][] linksTTimes) { - this.volumes = linksVolumes.clone(); - this.ttimes = linksTTimes.clone(); - } - } -} diff --git a/src/main/scala/beam/utils/SpatialPlot.scala b/src/main/scala/beam/utils/SpatialPlot.scala index d072344c0cf..e062f01db62 100755 --- a/src/main/scala/beam/utils/SpatialPlot.scala +++ b/src/main/scala/beam/utils/SpatialPlot.scala @@ -1,16 +1,11 @@ package beam.utils import java.awt._ -import java.awt.geom.Point2D -import java.awt.image.BufferedImage -import java.io.{BufferedWriter, File, FileWriter} - +import java.io.{BufferedWriter, FileWriter} import beam.agentsim.agents.ridehail.RideHailAgent -import javax.imageio.ImageIO import org.matsim.api.core.v01.{Coord, Id} import scala.collection.mutable.ListBuffer -import scala.util.Random case class PointToPlot(coord: Coord, color: Color, size: Int) case class LineToPlot(startCoord: Coord, endCoord: Coord, color: Color, stroke: Int) @@ -19,86 +14,12 @@ case class RideHailAgentInitCoord(agentId: Id[RideHailAgent], coord: Coord) case class Bounds(minx: Double, miny: Double, maxx: Double, maxy: Double) -class BoundsCalculator() { - var minX: Double = Double.MaxValue - var maxX: Double = Double.MinValue - var minY: Double = Double.MaxValue - var maxY: Double = Double.MinValue - - def addPoint(coord: Coord): Unit = { - minX = Math.min(minX, coord.getX) - minY = Math.min(minY, coord.getY) - maxX = Math.max(maxX, coord.getX) - maxY = Math.max(maxY, coord.getY) - } - - def getBound: Bounds = { - Bounds(minX, minY, maxX, maxY) - } - - def getImageProjectedCoordinates( - originalCoord: Coord, - width: Int, - height: Int, - frame: Int - ): Coord = { - val updatedWidth = width - 2 * frame - val updatedHeight = height - 2 * frame - - if (minX == maxX) { - new Coord(updatedWidth / 2, updatedHeight / 2) - } else { - new Coord( - frame + (originalCoord.getX - minX) / (maxX - minX) * updatedWidth, - frame + (originalCoord.getY - minY) / (maxY - minY) * updatedHeight - ) - } - } -} // frame is good for text lables as they can be outside of the area otherwise -class SpatialPlot(width: Int, height: Int, frame: Int) { - - val pointsToPlot: ListBuffer[PointToPlot] = ListBuffer() - - val linesToPlot: ListBuffer[LineToPlot] = ListBuffer() - - val stringsToPlot: ListBuffer[StringToPlot] = ListBuffer() +class SpatialPlot(width: Int, height: Int, frame: Int) extends Plot(width, height, frame) { val rideHailAgentInitCoordBuffer: ListBuffer[RideHailAgentInitCoord] = ListBuffer() - val bufferedImage = - new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) - - var boundsCalculator = new BoundsCalculator - - def setBoundsCalculator(boundsCalculator: BoundsCalculator) { - this.boundsCalculator = boundsCalculator - } - - def getBoundsCalculator: BoundsCalculator = { - boundsCalculator - } - - def addInvisiblePointsForBoundary(coord: Coord): Unit = { - boundsCalculator.addPoint(coord) - } - - def addLine(line: LineToPlot): Unit = { - linesToPlot += line - boundsCalculator.addPoint(line.startCoord) - boundsCalculator.addPoint(line.endCoord) - } - - def addString(stringToPlot: StringToPlot): Unit = { - stringsToPlot += stringToPlot - boundsCalculator.addPoint(stringToPlot.coord) - } - - def addPoint(point: PointToPlot): Unit = { - pointsToPlot += point - boundsCalculator.addPoint(point.coord) - } def addAgentWithCoord(rideHailAgentInitCoord: RideHailAgentInitCoord): Unit = { rideHailAgentInitCoordBuffer += rideHailAgentInitCoord @@ -115,159 +36,5 @@ class SpatialPlot(width: Int, height: Int, frame: Int) { out.close() } - def writeImage(path: String): Unit = { - val graphics2d = bufferedImage.createGraphics() - - for (lineToPlot <- linesToPlot) { - //val stroke = new BasicStroke(lineToPlot.stroke) - //graphics2d.setStroke(stroke) - graphics2d.setColor(lineToPlot.color) - val projectedStartCoord = - boundsCalculator.getImageProjectedCoordinates(lineToPlot.startCoord, width, height, frame) - val projectedEndCoord = - boundsCalculator.getImageProjectedCoordinates(lineToPlot.endCoord, width, height, frame) - - drawArrow( - graphics2d, - new Point2D.Double(projectedStartCoord.getX, projectedStartCoord.getY), - new Point2D.Double(projectedEndCoord.getX, projectedEndCoord.getY), - new BasicStroke(lineToPlot.stroke), - new BasicStroke(lineToPlot.stroke * 10), - lineToPlot.stroke * 10 - ) - - //graphics2d.drawLine(projectedStartCoord.getX.toInt, projectedStartCoord.getY.toInt, projectedEndCoord.getX.toInt, projectedEndCoord.getY.toInt) - } - - for (pointToPlot <- pointsToPlot) { - graphics2d.setColor(pointToPlot.color) - val projectedCoord = - boundsCalculator.getImageProjectedCoordinates(pointToPlot.coord, width, height, frame) - graphics2d.fillOval( - projectedCoord.getX.toInt, - projectedCoord.getY.toInt, - pointToPlot.size, - pointToPlot.size - ) - } - - for (stringToPlot <- stringsToPlot) { - val font = new Font("Serif", Font.PLAIN, stringToPlot.fontSize) - graphics2d.setFont(font) - graphics2d.setColor(stringToPlot.color) - val projectedCoord = - boundsCalculator.getImageProjectedCoordinates(stringToPlot.coord, width, height, frame) - graphics2d.drawString(stringToPlot.text, projectedCoord.getX.toInt, projectedCoord.getY.toInt) - } - - val index = path.lastIndexOf("/") - val outDir = new File(path.substring(0, index)) - if (!outDir.exists()) outDir.mkdirs() - ImageIO.write(bufferedImage, "PNG", new File(path)) - } - - def drawArrow( - gfx: Graphics2D, - start: Point2D, - end: Point2D, - lineStroke: Stroke, - arrowStroke: Stroke, - arrowSize: Float - ): Unit = { - import java.awt.geom.GeneralPath - - val startx = start.getX - val starty = start.getY - - gfx.setStroke(arrowStroke) - val deltax = startx - end.getX - var result = .0 - if (deltax == 0.0d) result = Math.PI / 2 - else - result = Math.atan((starty - end.getY) / deltax) + (if (startx < end.getX) - Math.PI - else 0) - - val angle = result - - val arrowAngle = Math.PI / 12.0d - - val x1 = arrowSize * Math.cos(angle - arrowAngle) - val y1 = arrowSize * Math.sin(angle - arrowAngle) - val x2 = arrowSize * Math.cos(angle + arrowAngle) - val y2 = arrowSize * Math.sin(angle + arrowAngle) - - val cx = (arrowSize / 2.0f) * Math.cos(angle) - val cy = (arrowSize / 2.0f) * Math.sin(angle) - - val polygon = new GeneralPath - polygon.moveTo(end.getX, end.getY) - polygon.lineTo(end.getX + x1, end.getY + y1) - polygon.lineTo(end.getX + x2, end.getY + y2) - polygon.closePath() - gfx.fill(polygon) - - gfx.setStroke(lineStroke) - gfx.drawLine( - startx.toInt, - starty.toInt, - (end.getX + cx).asInstanceOf[Int], - (end.getY + cy).asInstanceOf[Int] - ) - } - -} - -object SpatialPlot extends App { - /* - val bi = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_ARGB); - - val ig2 = bi.createGraphics(); - //Draw some lines to the graphic - - - //ig2.fillOval("sfdsfa", Random.nextFloat() * 1000, Random.nextFloat() * 1000) - - ig2.setColor(Color.BLACK) - for (i <- 1 until 10) { - ig2.fillOval(Random.nextInt(1000), Random.nextInt(1000), 5, 5) - } - - ig2.setColor(Color.BLUE) - for (i <- 1 until 10) { - ig2.fillOval(Random.nextInt(1000), Random.nextInt(1000), 5, 5) - } - - - //ig2.drawLine(x1,y1,x2,y2); - //ig2.drawLine(x2,y2,x3,y3); - //... - - //Export the result to a file - ImageIO.write(bi, "PNG", new File("c:\\temp\\name.png")); - */ - - val spatialPlot = new SpatialPlot(1000, 1000, 20) - - (1 until 100).foreach { _ => - spatialPlot.addPoint( - PointToPlot(new Coord(Random.nextDouble(), Random.nextDouble()), Color.blue, 5) - ) - } - - spatialPlot.addLine( - LineToPlot( - new Coord(Random.nextDouble(), Random.nextDouble()), - new Coord(Random.nextDouble(), Random.nextDouble()), - Color.blue, - 2 - ) - ) - - spatialPlot.addString( - StringToPlot("X", new Coord(Random.nextDouble(), Random.nextDouble()), Color.green, 100) - ) - - spatialPlot.writeImage("c:\\temp\\name.png") -} +} \ No newline at end of file