Skip to content

Commit

Permalink
enable/disable ids and names csv with string flags
Browse files Browse the repository at this point in the history
  • Loading branch information
abyrd committed Feb 2, 2024
1 parent 06d9bee commit d5f5bec
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -175,6 +176,11 @@ public class AnalysisRequest {
*/
public int dualAccessibilityThreshold = 0;

/**
* Freeform (untyped) flags for enabling experimental, undocumented, or arcane behavior in backend or workers.
* This should be used to replace all previous special behavior flags that were embedded inside analysis names etc.
*/
public Set<String> flags;

/**
* Create the R5 `Scenario` from this request.
Expand Down Expand Up @@ -281,6 +287,7 @@ public void populateTask (AnalysisWorkerTask task, UserPermissions userPermissio

task.includeTemporalDensity = includeTemporalDensity;
task.dualAccessibilityThreshold = dualAccessibilityThreshold;
task.flags = flags;
}

private EnumSet<LegMode> getEnumSetFromString (String s) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import java.util.Arrays;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
Expand Down Expand Up @@ -177,6 +178,12 @@ public abstract class AnalysisWorkerTask extends ProfileRequest {
*/
public ChaosParameters injectFault;

/**
* Freeform (untyped) flags for enabling experimental, undocumented, or arcane worker behavior.
* This should be used to replace all previous special behavior flags that were embedded inside analysis names etc.
*/
public Set<String> flags;

/**
* Is this a single point or regional request? Needed to encode types in JSON serialization. Can that type field be
* added automatically with a serializer annotation instead of by defining a getter method and two dummy methods?
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/com/conveyal/r5/analyst/cluster/PathResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.ID_ONLY;
import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.ID_AND_NAME;
import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.NAME_ONLY;
import static com.google.common.base.Preconditions.checkState;

/**
Expand Down Expand Up @@ -47,8 +50,11 @@ public class PathResult {
* With additional changes, patterns could be collapsed further to route combinations or modes.
*/
public final Multimap<RouteSequence, Iteration>[] iterationsForPathTemplates;

private final TransitLayer transitLayer;

private TransitLayer.EntityRepresentation nameOrId;

public static final String[] DATA_COLUMNS = new String[]{
"routes",
"boardStops",
Expand Down Expand Up @@ -76,6 +82,17 @@ public PathResult(AnalysisWorkerTask task, TransitLayer transitLayer) {
}
iterationsForPathTemplates = new Multimap[nDestinations];
this.transitLayer = transitLayer;
if (task.flags == null) {
nameOrId = ID_ONLY;
} else {
boolean includeEntityNames = task.flags.contains("csv_names");
boolean includeEntityIds = !task.flags.contains("csv_no_ids");
if (includeEntityIds && includeEntityNames) {
this.nameOrId = ID_AND_NAME;
} else if (includeEntityNames) {
this.nameOrId = NAME_ONLY;
}
}
}

/**
Expand Down Expand Up @@ -108,7 +125,7 @@ public ArrayList<String[]>[] summarizeIterations(Stat stat) {
int nIterations = iterations.size();
checkState(nIterations > 0, "A path was stored without any iterations");
String waits = null, transfer = null, totalTime = null;
String[] path = routeSequence.detailsWithGtfsIds(transitLayer, true);
String[] path = routeSequence.detailsWithGtfsIds(transitLayer, nameOrId);
double targetValue;
IntStream totalWaits = iterations.stream().mapToInt(i -> i.waitTimes.sum());
if (stat == Stat.MINIMUM) {
Expand Down
57 changes: 44 additions & 13 deletions src/main/java/com/conveyal/r5/transit/TransitLayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;

import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.ID_ONLY;
import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.NAME_ONLY;


/**
* A key simplifying factor is that we don't handle overnight trips. This is fine for analysis at usual times of day.
Expand Down Expand Up @@ -815,31 +818,59 @@ public TIntSet findStopsInGeometry (Geometry geometry) {
return stops;
}

public enum EntityRepresentation {
ID_ONLY, NAME_ONLY, ID_AND_NAME
}

/**
* For the given pattern index, returns the GTFS routeId. If includeName is true, the returned string will
* also include a route_short_name or route_long_name (if they are not null).
*/
public String routeString(int routeIndex, boolean includeName) {
public String routeString (int routeIndex, EntityRepresentation nameOrId) {
RouteInfo routeInfo = routes.get(routeIndex);
String route = routeInfo.route_id;
if (includeName) {
if (routeInfo.route_short_name != null) {
route += " (" + routeInfo.route_short_name + ")";
} else if (routeInfo.route_long_name != null){
route += " (" + routeInfo.route_long_name + ")";
String name = routeInfo.route_short_name;
String id = routeInfo.route_id;
// If we might actually use the name, check some fallbacks.
if (nameOrId != ID_ONLY) {
if (name == null) {
name = routeInfo.route_long_name;
}
if (name == null) {
name = routeInfo.route_id;
}
}
return route;
return switch (nameOrId) {
case NAME_ONLY -> name;
case ID_AND_NAME -> id + " (" + name + ")";
default -> id;
};
}

/**
* For the given stop index, returns the GTFS stopId (stripped of R5's feedId prefix) and, if includeName is true,
* stopName.
*/
public String stopString(int stopIndex, boolean includeName) {
// TODO use a compact feed index, instead of splitting to remove feedIds
String stop = stopIdForIndex.get(stopIndex) == null ? "[new]" : stopIdForIndex.get(stopIndex).split(":")[1];
if (includeName) stop += " (" + stopNames.get(stopIndex) + ")";
return stop;
public String stopString(int stopIndex, EntityRepresentation nameOrId) {
String stopId = stopIdForIndex.get(stopIndex);
String stopName = stopNames.get(stopIndex);
// I'd trust the JVM JIT to optimize out these assignments on different code paths, but not the split call.
if (nameOrId != NAME_ONLY) {
if (stopId == null) {
stopId = "[new]";
} else {
// TODO use a compact feed ID instead of splitting to remove feedIds (or put feedId into another CSV field)
stopId = stopId.split(":")[1];
}
}
if (nameOrId != ID_ONLY) {
if (stopName == null) {
stopName = "[new]";
}
}
return switch (nameOrId) {
case NAME_ONLY -> stopName;
case ID_AND_NAME -> stopId + " (" + stopName + ")";
default -> stopId;
};
}
}
17 changes: 10 additions & 7 deletions src/main/java/com/conveyal/r5/transit/path/RouteSequence.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.conveyal.r5.transit.path;

import com.conveyal.r5.transit.TransitLayer;
import com.conveyal.r5.transit.TransitLayer.EntityRepresentation;
import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;

Expand All @@ -9,6 +10,8 @@
import java.util.Objects;
import java.util.StringJoiner;

import static com.conveyal.r5.transit.TransitLayer.EntityRepresentation.ID_AND_NAME;

/** A door-to-door path that includes the routes ridden between stops */
public class RouteSequence {

Expand All @@ -28,15 +31,15 @@ public RouteSequence(PatternSequence patternSequence, TransitLayer transitLayer)
}

/** Returns details summarizing this route sequence, using GTFS ids stored in the supplied transitLayer. */
public String[] detailsWithGtfsIds(TransitLayer transitLayer, boolean includeNames){
public String[] detailsWithGtfsIds (TransitLayer transitLayer, EntityRepresentation nameOrId){
StringJoiner routeIds = new StringJoiner("|");
StringJoiner boardStopIds = new StringJoiner("|");
StringJoiner alightStopIds = new StringJoiner("|");
StringJoiner rideTimes = new StringJoiner("|");
for (int i = 0; i < routes.size(); i++) {
routeIds.add(transitLayer.routeString(routes.get(i), includeNames));
boardStopIds.add(transitLayer.stopString(stopSequence.boardStops.get(i), includeNames));
alightStopIds.add(transitLayer.stopString(stopSequence.alightStops.get(i), includeNames));
routeIds.add(transitLayer.routeString(routes.get(i), nameOrId));
boardStopIds.add(transitLayer.stopString(stopSequence.boardStops.get(i), nameOrId));
alightStopIds.add(transitLayer.stopString(stopSequence.alightStops.get(i), nameOrId));
rideTimes.add(String.format("%.1f", stopSequence.rideTimesSeconds.get(i) / 60f));
}
String accessTime = stopSequence.access == null ? null : String.format("%.1f", stopSequence.access.time / 60f);
Expand All @@ -55,9 +58,9 @@ public String[] detailsWithGtfsIds(TransitLayer transitLayer, boolean includeNam
public Collection<TransitLeg> transitLegs(TransitLayer transitLayer) {
Collection<TransitLeg> transitLegs = new ArrayList<>();
for (int i = 0; i < routes.size(); i++) {
String routeString = transitLayer.routeString(routes.get(i), true);
String boardStop = transitLayer.stopString(stopSequence.boardStops.get(i), true);
String alightStop = transitLayer.stopString(stopSequence.alightStops.get(i), true);
String routeString = transitLayer.routeString(routes.get(i), ID_AND_NAME);
String boardStop = transitLayer.stopString(stopSequence.boardStops.get(i), ID_AND_NAME);
String alightStop = transitLayer.stopString(stopSequence.alightStops.get(i), ID_AND_NAME);
transitLegs.add(new TransitLeg(routeString, stopSequence.rideTimesSeconds.get(i), boardStop, alightStop));
}
return transitLegs;
Expand Down

0 comments on commit d5f5bec

Please sign in to comment.