
org.opentripplanner.graph_builder.GraphStats Maven / Gradle / Ivy
package org.opentripplanner.graph_builder;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.csvreader.CsvWriter;
import com.google.common.collect.Multiset;
import com.google.common.collect.TreeMultiset;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.geotools.referencing.GeodeticCalculator;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.linearref.LinearLocation;
import org.locationtech.jts.linearref.LocationIndexedLine;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.SerializedGraphObject;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.opentripplanner.routing.vertextype.TransitStopVertex;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.service.TransitModel;
import org.opentripplanner.util.OtpAppException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GraphStats {
private static final Logger LOG = LoggerFactory.getLogger(GraphStats.class);
@Parameter(names = { "-v", "--verbose" }, description = "Verbose output")
private final boolean verbose = false;
@Parameter(names = { "-d", "--debug" }, description = "Debug mode")
private final boolean debug = false;
private final CommandEndpoints commandEndpoints = new CommandEndpoints();
private final CommandPatternStats commandPatternStats = new CommandPatternStats();
private final JCommander jc;
@Parameter(
names = { "-h", "--help" },
description = "Print this help message and exit",
help = true
)
private boolean help;
@Parameter(names = { "-g", "--graph" }, description = "path to the graph file", required = true)
private String graphPath;
@Parameter(names = { "-o", "--out" }, description = "output file")
private String outPath;
private Graph graph;
private TransitModel transitModel;
private CsvWriter writer;
private GraphStats(String[] args) {
jc = new JCommander(this);
jc.addCommand(commandEndpoints);
jc.addCommand(commandPatternStats);
try {
jc.parse(args);
} catch (Exception e) {
System.out.println(e.getMessage());
jc.usage();
System.exit(1);
}
if (help || jc.getParsedCommand() == null) {
jc.usage();
System.exit(0);
}
}
public static void main(String[] args) {
GraphStats graphStats = new GraphStats(args);
try {
graphStats.run();
} catch (OtpAppException ignore) {
// The error is handled at a lover level
}
}
private void run() {
/* open input graph (same for all commands) */
File graphFile = new File(graphPath);
SerializedGraphObject serializedGraphObject = SerializedGraphObject.load(graphFile);
graph = serializedGraphObject.graph;
transitModel = serializedGraphObject.transitModel;
/* open output stream (same for all commands) */
if (outPath != null) {
try {
writer = new CsvWriter(outPath, ',', StandardCharsets.UTF_8);
} catch (Exception e) {
LOG.error("Exception while opening output file " + outPath);
return;
}
} else {
writer = new CsvWriter(System.out, ',', StandardCharsets.UTF_8);
}
LOG.info("done loading graph.");
String command = jc.getParsedCommand();
if (command.equals("endpoints")) {
commandEndpoints.run();
} else if (command.equals("patternstats")) {
commandPatternStats.run();
}
writer.close();
}
@Parameters(
commandNames = "endpoints",
commandDescription = "Generate random endpoints for performance testing"
)
class CommandEndpoints {
@Parameter(names = { "-r", "--radius" }, description = "perturbation radius in meters")
private final double radius = 100;
@Parameter(names = { "-n", "--number" }, description = "number of endpoints to generate")
private final int n = 20;
@Parameter(
names = { "-s", "--stops" },
description = "choose endpoints near stops not street vertices"
)
private final boolean useStops = false;
@Parameter(
names = { "-rs", "--seed" },
description = "random seed, allows reproducible results"
)
private final Long seed = null;
// go along road then random
public void run() {
LOG.info(
String.format(
"Producing %d random endpoints within radius %2.2fm around %s.",
n,
radius,
useStops ? "stops" : "streets"
)
);
List vertices = new ArrayList<>();
GeodeticCalculator gc = new GeodeticCalculator();
Class> klasse = useStops ? TransitStopVertex.class : StreetVertex.class;
for (Vertex v : graph.getVertices()) if (klasse.isInstance(v)) vertices.add(v);
Random random = new Random();
if (seed != null) random.setSeed(seed);
Collections.shuffle(vertices, random);
vertices = vertices.subList(0, n);
try {
writer.writeRecord(new String[] { "n", "name", "lon", "lat" });
int i = 0;
for (Vertex v : vertices) {
Coordinate c;
if (v instanceof StreetVertex) {
LineString ls = ((StreetVertex) v).getOutgoing().iterator().next().getGeometry();
int numPoints = ls.getNumPoints();
LocationIndexedLine lil = new LocationIndexedLine(ls);
int seg = random.nextInt(numPoints);
double frac = random.nextDouble();
LinearLocation ll = new LinearLocation(seg, frac);
c = lil.extractPoint(ll);
} else {
c = v.getCoordinate();
}
// perturb
double distance = random.nextDouble() * radius;
double azimuth = random.nextDouble() * 360 - 180;
// double x = c.x + r * Math.cos(theta);
// double y = c.y + r * Math.sin(theta);
gc.setStartingGeographicPoint(c.x, c.y);
gc.setDirection(azimuth, distance);
Point2D dest = gc.getDestinationGeographicPoint();
String name = v.getDefaultName();
String[] entries = new String[] {
Integer.toString(i),
name,
Double.toString(dest.getX()),
Double.toString(dest.getY()),
};
writer.writeRecord(entries);
i += 1;
}
} catch (IOException ioe) {
LOG.error("Excpetion while writing CSV: {}", ioe.getMessage());
}
LOG.info("done.");
}
}
@Parameters(commandNames = "patternstats", commandDescription = "trip pattern stats")
class CommandPatternStats {
public void run() {
LOG.info("counting number of trips per pattern...");
try {
writer.writeRecord(
new String[] {
"nTripsInPattern",
"frequency",
"cumulativePatterns",
"empiricalDistPatterns",
"cumulativeTrips",
"empiricalDistTrips",
}
);
Collection patterns = transitModel.getAllTripPatterns();
Multiset counts = TreeMultiset.create();
int nPatterns = patterns.size();
LOG.info("total number of patterns is: {}", nPatterns);
int nTrips = 0;
for (TripPattern ttp : patterns) {
int patternNumTrips = (int) ttp.scheduledTripsAsStream().count();
counts.add(patternNumTrips);
nTrips += patternNumTrips;
}
LOG.info("total number of trips is: {}", nTrips);
LOG.info("average number of trips per pattern is: {}", nTrips / nPatterns);
int cPatterns = 0;
int cTrips = 0;
for (Multiset.Entry count : counts.entrySet()) {
cPatterns += count.getCount();
cTrips += count.getCount() * count.getElement();
writer.writeRecord(
new String[] {
count.getElement().toString(),
Integer.toString(count.getCount()),
Integer.toString(cPatterns),
Double.toString(cPatterns / (double) nPatterns),
Integer.toString(cTrips),
Double.toString(cTrips / (double) nTrips),
}
);
}
} catch (IOException e) {
LOG.error("Exception writing CSV: {}", e.getMessage());
return;
}
LOG.info("done.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy