diff --git a/.github/workflows/jar-and-R-ci.yaml b/.github/workflows/ci.yml similarity index 54% rename from .github/workflows/jar-and-R-ci.yaml rename to .github/workflows/ci.yml index 5c3235ed4..18274cf24 100644 --- a/.github/workflows/jar-and-R-ci.yaml +++ b/.github/workflows/ci.yml @@ -2,88 +2,9 @@ name: CI on: push: - paths: - - java-r5rcore/** - - r-package/** - - .github/workflows/** jobs: - build-jar: - env: - GH_TOKEN: ${{ github.token }} - - runs-on: ubuntu-latest - - # don't build on merges to master - if: ${{ !github.ref_protected }} - - steps: - - uses: actions/checkout@v3 - - name: Set up R - uses: r-lib/actions/setup-r@v2 -# with: -# use-public-rspm: true # this no longer works as of September 2025 - - - name: Install R packages - run: | - # this specification is necessary for some reason as of September 2025 - options(repos = c(CRAN = "https://packagemanager.posit.co/cran/__linux__/noble/latest")) - install.packages(c('devtools', 'remotes')) - remotes::install_deps(dependencies = TRUE) - shell: Rscript {0} - working-directory: r-package - - - name: Install system dependencies - run: | - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') - working-directory: r-package - - - name: Set up JDK 21 - uses: actions/setup-java@v3 - with: - java-version: '21' - distribution: 'temurin' - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v2 - - name: Build with Gradle - uses: gradle/gradle-build-action@749f47bda3e44aa060e82d7b3ef7e40d953bd629 - with: - arguments: build - build-root-directory: java-r5rcore - - - name: Create pull request - # https://github.com/actions/checkout/pull/1184 - run: | - NEW_JAR="java-r5rcore/build/libs/java-r5rcore-*.jar" - TARGET_JAR="r-package/inst/jar/r5r.jar" - - new_sha=$(sha256sum $NEW_JAR | awk '{print $1}') - # ensure file exists and then compute sha - old_sha=$( [ -f "$TARGET_JAR" ] && sha256sum "$TARGET_JAR" | awk '{print $1}' || echo "" ) - - echo "NEW: $new_sha" - echo "OLD: $old_sha" - - # Only push if sha different - if [ "$new_sha" != "$old_sha" ]; then - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - echo "JAR changed — updating." - mv $NEW_JAR $TARGET_JAR - git add $TARGET_JAR - git commit -m "Rebuild JAR for commit ${GITHUB_SHA}" - git push - else - echo "JAR unchanged — skipping commit." - fi - R-CMD-check: - needs: build-jar - runs-on: ${{ matrix.config.os }} name: R-CMD-check ${{ matrix.config.os }} (R ${{ matrix.config.r }}) @@ -107,11 +28,8 @@ jobs: with: fetch-depth: 0 - - name: Sync to latest HEAD including rebuilt JAR - run: | - git fetch origin "${{ github.ref_name }}" - git checkout "${{ github.ref_name }}" - git pull origin "${{ github.ref_name }}" + # ensure our gradle wrapper is correct, https://github.com/gradle/actions/blob/main/docs/wrapper-validation.md + - uses: gradle/actions/wrapper-validation@v5 - uses: r-lib/actions/setup-r@v2 with: @@ -147,8 +65,6 @@ jobs: working-directory: r-package R-CMD-check-CRAN: - needs: build-jar - runs-on: ${{ matrix.config.os }} name: R-CMD-check-CRAN @@ -168,12 +84,6 @@ jobs: with: fetch-depth: 0 - - name: Sync to latest HEAD including rebuilt JAR - run: | - git fetch origin "${{ github.ref_name }}" - git checkout "${{ github.ref_name }}" - git pull origin "${{ github.ref_name }}" - - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} @@ -194,8 +104,6 @@ jobs: NOT_CRAN: false test-coverage: - needs: build-jar - runs-on: ubuntu-22.04 steps: @@ -203,12 +111,6 @@ jobs: with: fetch-depth: 0 - - name: Sync to latest HEAD including rebuilt JAR - run: | - git fetch origin "${{ github.ref_name }}" - git checkout "${{ github.ref_name }}" - git pull origin "${{ github.ref_name }}" - - uses: r-lib/actions/setup-r@v2 - name: Java setup diff --git a/.gitignore b/.gitignore index 2f0b5cec2..35f5c5215 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ java-api/out java-api/target java-r5/target r-package/.Rproj.user +r-package/inst/jar/* +!r-package/inst/jar/.gitkeep r-package/.Rhistory R5.jar r5r_core.jar @@ -15,15 +17,16 @@ poa_osm.pbf.mapdb poa_osm.pbf.mapdb.p /r-package/inst/extdata/spo/spo_osm.pbf.mapdb /r-package/inst/extdata/spo/spo_osm.pbf.mapdb.p -java-r5rcore/out/artifacts/r5r_jar/r5r.jar -java-r5rcore/out/production/r5r/org/ipea/r5r/DetailedItineraryPlanner.class -java-r5rcore/out/production/r5r/org/ipea/r5r/R5RCore.class -java-r5rcore/out/production/r5r/org/ipea/r5r/RDataFrame.class -java-r5rcore/out/production/r5r/org/ipea/r5r/TravelTimeMatrixComputer.class -java-r5rcore/out -java-r5rcore/libs +r-package/java/out/artifacts/r5r_jar/r5r.jar +r-package/java/out/production/r5r/org/ipea/r5r/DetailedItineraryPlanner.class +r-package/java/out/production/r5r/org/ipea/r5r/R5RCore.class +r-package/java/out/production/r5r/org/ipea/r5r/RDataFrame.class +r-package/java/out/production/r5r/org/ipea/r5r/TravelTimeMatrixComputer.class +r-package/java/out +r-package/java/libs +r-package/java/build .DS_Store -java-r5rcore/target +r-package/java/target .*.swp jpa-buddy.xml r5-*.jar diff --git a/java-r5rcore/src/org/ipea/r5r/Network/TransitLayerWithShapes.java b/java-r5rcore/src/org/ipea/r5r/Network/TransitLayerWithShapes.java deleted file mode 100644 index 94a5a1518..000000000 --- a/java-r5rcore/src/org/ipea/r5r/Network/TransitLayerWithShapes.java +++ /dev/null @@ -1,329 +0,0 @@ -package org.ipea.r5r.Network; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.*; -import com.conveyal.r5.transit.*; -import com.conveyal.r5.util.LocationIndexedLineInLocalCoordinateSystem; -import com.google.common.base.Strings; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import gnu.trove.list.TIntList; -import gnu.trove.list.array.TIntArrayList; -import gnu.trove.map.TObjectIntMap; -import gnu.trove.map.hash.TObjectIntHashMap; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.linearref.LinearLocation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.DateTimeException; -import java.time.ZoneId; -import java.time.zone.ZoneRulesException; -import java.util.*; -import java.util.stream.DoubleStream; -import java.util.stream.StreamSupport; - -public class TransitLayerWithShapes extends TransitLayer { - - public static final boolean SAVE_SHAPES = true; - - private static final Logger LOG = LoggerFactory.getLogger(TransitLayerWithShapes.class); - - /** - * Load data from a GTFS feed. Call multiple times to load multiple feeds. - * The supplied feed is treated as read-only, and is not closed after being loaded. - * This method requires findPatterns() to have been called on the feed before it's passed in. - */ - public void loadFromGtfs (GTFSFeed gtfs, TransitLayer.LoadLevel level) throws DuplicateFeedException { - if (feedChecksums.containsKey(gtfs.feedId)) { - throw new DuplicateFeedException(gtfs.feedId); - } - - // checksum feed and add to checksum cache - feedChecksums.put(gtfs.feedId, gtfs.checksum); - - // Load stops. - // ID is the GTFS string ID, stopIndex is the zero-based index, stopVertexIndex is the index in the street layer. - TObjectIntMap indexForUnscopedStopId = new TObjectIntHashMap<>(); - stopsWheelchair = new BitSet(gtfs.stops.size()); - for (Stop stop : gtfs.stops.values()) { - int stopIndex = stopIdForIndex.size(); - String scopedStopId = String.join(":", stop.feed_id, stop.stop_id); - // This is only used while building the TransitNetwork to look up StopTimes from the same feed. - indexForUnscopedStopId.put(stop.stop_id, stopIndex); - stopIdForIndex.add(scopedStopId); - // intern zone IDs to save memory - fareZoneForStop.add(stop.zone_id); - parentStationIdForStop.add(stop.parent_station); - stopForIndex.add(stop); - if (stop.wheelchair_boarding != null && stop.wheelchair_boarding.trim().equals("1")) { - stopsWheelchair.set(stopIndex); - } - if (level == TransitLayer.LoadLevel.FULL) { - stopNames.add(stop.stop_name); - } - } - - // Load service periods, assigning integer codes which will be referenced by trips and patterns. - TObjectIntMap serviceCodeNumber = new TObjectIntHashMap<>(20, 0.5f, -1); - gtfs.services.forEach((serviceId, service) -> { - int serviceIndex = services.size(); - services.add(service); - serviceCodeNumber.put(serviceId, serviceIndex); - LOG.debug("Service {} has ID {}", serviceIndex, serviceId); - }); - - LOG.info("Creating trip patterns and schedules."); - - // These are temporary maps used only for grouping purposes. - Map tripPatternForPatternId = new HashMap<>(); - Multimap tripsForBlock = HashMultimap.create(); - - // Keyed with unscoped route_id, which is fine as this is for a single GTFS feed - TObjectIntMap routeIndexForRoute = new TObjectIntHashMap<>(); - int nTripsAdded = 0; - int nZeroDurationHops = 0; - TRIPS: for (String tripId : gtfs.trips.keySet()) { - Trip trip = gtfs.trips.get(tripId); - Route route = gtfs.routes.get(trip.route_id); - // Construct the stop pattern and schedule for this trip. - String scopedRouteId = String.join(":", gtfs.feedId, trip.route_id); - TIntList arrivals = new TIntArrayList(TYPICAL_NUMBER_OF_STOPS_PER_TRIP); - TIntList departures = new TIntArrayList(TYPICAL_NUMBER_OF_STOPS_PER_TRIP); - TIntList stopSequences = new TIntArrayList(TYPICAL_NUMBER_OF_STOPS_PER_TRIP); - - int previousDeparture = Integer.MIN_VALUE; - - int nStops = 0; - - Iterable stopTimes; - - try { - stopTimes = gtfs.getInterpolatedStopTimesForTrip(tripId); - } catch (GTFSFeed.FirstAndLastStopsDoNotHaveTimes e) { - LOG.warn("First and last stops do not both have times specified on trip {} on route {}, skipping this as interpolation is impossible", trip.trip_id, trip.route_id); - continue TRIPS; - } - - for (StopTime st : stopTimes) { - arrivals.add(st.arrival_time); - departures.add(st.departure_time); - stopSequences.add(st.stop_sequence); - - if (previousDeparture > st.arrival_time || st.arrival_time > st.departure_time) { - LOG.warn("Negative-time travel at stop {} on trip {} on route {}, skipping this trip as it will wreak havoc with routing", st.stop_id, trip.trip_id, trip.route_id); - continue TRIPS; - } - - if (previousDeparture == st.arrival_time) { //Teleportation: arrive at downstream stop immediately after departing upstream - //often the result of a stop_times input with time values rounded to the nearest minute. - //TODO check if the distance of the hop is reasonably traveled in less than 60 seconds, which may vary by mode. - nZeroDurationHops++; - } - - previousDeparture = st.departure_time; - - nStops++; - } - - if (nStops == 0) { - LOG.warn("Trip {} on route {} {} has no stops, it will not be used", trip.trip_id, trip.route_id, route.route_short_name); - continue; - } - - String patternId = gtfs.patternForTrip.get(tripId); - - TripPattern tripPattern = tripPatternForPatternId.get(patternId); - if (tripPattern == null) { - tripPattern = new TripPattern(String.format("%s:%s", gtfs.feedId, route.route_id), stopTimes, indexForUnscopedStopId); - - // if we haven't seen the route yet _from this feed_ (as IDs are only feed-unique) - // create it. - if (level == TransitLayer.LoadLevel.FULL) { - if (!routeIndexForRoute.containsKey(trip.route_id)) { - int routeIndex = routes.size(); - RouteInfo ri = new RouteInfo(route, gtfs.agency.get(route.agency_id)); - routes.add(ri); - routeIndexForRoute.put(trip.route_id, routeIndex); - } - - tripPattern.routeIndex = routeIndexForRoute.get(trip.route_id); - - if (trip.shape_id != null && SAVE_SHAPES) { - Shape shape = gtfs.getShape(trip.shape_id); - if (shape == null) LOG.warn("Shape {} for trip {} was missing", trip.shape_id, trip.trip_id); - else { - // TODO this will not work if some trips in the pattern don't have shapes - tripPattern.shape = shape.geometry; - - // project stops onto shape - boolean stopsHaveShapeDistTraveled = StreamSupport.stream(stopTimes.spliterator(), false) - .noneMatch(st -> Double.isNaN(st.shape_dist_traveled)); - boolean shapePointsHaveDistTraveled = DoubleStream.of(shape.shape_dist_traveled) - .noneMatch(Double::isNaN); - - LinearLocation[] locations; - - if (stopsHaveShapeDistTraveled && shapePointsHaveDistTraveled) { - // create linear locations from dist traveled - locations = StreamSupport.stream(stopTimes.spliterator(), false) - .map(st -> { - double dist = st.shape_dist_traveled; - - int segment = 0; - - while (segment < shape.shape_dist_traveled.length - 2 && - dist > shape.shape_dist_traveled[segment + 1] - ) segment++; - - double endSegment = shape.shape_dist_traveled[segment + 1]; - double beginSegment = shape.shape_dist_traveled[segment]; - double proportion = (dist - beginSegment) / (endSegment - beginSegment); - - return new LinearLocation(segment, proportion); - }).toArray(LinearLocation[]::new); - } else { - // naive snapping - LocationIndexedLineInLocalCoordinateSystem line = - new LocationIndexedLineInLocalCoordinateSystem(shape.geometry.getCoordinates()); - - locations = StreamSupport.stream(stopTimes.spliterator(), false) - .map(st -> { - Stop stop = gtfs.stops.get(st.stop_id); - return line.project(new Coordinate(stop.stop_lon, stop.stop_lat)); - }) - .toArray(LinearLocation[]::new); - } - - tripPattern.stopShapeSegment = new int[locations.length]; - tripPattern.stopShapeFraction = new float[locations.length]; - - for (int i = 0; i < locations.length; i++) { - tripPattern.stopShapeSegment[i] = locations[i].getSegmentIndex(); - tripPattern.stopShapeFraction[i] = (float) locations[i].getSegmentFraction(); - } - } - } - } - - tripPatternForPatternId.put(patternId, tripPattern); - tripPattern.originalId = tripPatterns.size(); - tripPatterns.add(tripPattern); - } - tripPattern.setOrVerifyDirection(trip.direction_id); - int serviceCode = serviceCodeNumber.get(trip.service_id); - - // TODO there's no reason why we can't just filter trips like this, correct? - // TODO this means that invalid trips still have empty patterns created - Collection frequencies = gtfs.getFrequencies(trip.trip_id); - TripSchedule tripSchedule = TripSchedule.create(trip, arrivals.toArray(), departures.toArray(), frequencies, stopSequences.toArray(), serviceCode); - if (tripSchedule == null) continue; - - tripPattern.addTrip(tripSchedule); - - this.hasFrequencies = this.hasFrequencies || tripSchedule.headwaySeconds != null; - this.hasSchedules = this.hasSchedules || tripSchedule.headwaySeconds == null; - - nTripsAdded += 1; - // Record which block this trip belongs to, if any. - if ( ! Strings.isNullOrEmpty(trip.block_id)) { - tripsForBlock.put(trip.block_id, tripSchedule); - } - } - LOG.info("Done creating {} trips on {} patterns.", nTripsAdded, tripPatternForPatternId.size()); - - LOG.info("{} zero-duration hops found.", nZeroDurationHops); - - LOG.info("Chaining trips together according to blocks to model interlining..."); - // Chain together trips served by the same vehicle that allow transfers by simply staying on board. - // Elsewhere this is done by grouping by (serviceId, blockId) but this is not supported by the spec. - // Discussion started on gtfs-changes. - tripsForBlock.asMap().forEach((blockId, trips) -> { - TripSchedule[] schedules = trips.toArray(new TripSchedule[trips.size()]); - Arrays.sort(schedules); // Sorts on first departure time - for (int i = 0; i < schedules.length - 1; i++) { - schedules[i].chainTo(schedules[i + 1]); - } - }); - LOG.info("Done chaining trips together according to blocks."); - - LOG.info("Sorting trips on each pattern"); - for (TripPattern tripPattern : tripPatternForPatternId.values()) { - Collections.sort(tripPattern.tripSchedules); - } - LOG.info("done sorting"); - - LOG.info("Finding the approximate center of the transport network..."); - findCenter(gtfs.stops.values()); - - //Set transportNetwork timezone - //If there are no agencies (which is strange) it is GMT - //Otherwise it is set to first valid agency timezone and warning is shown if agencies have different timezones - if (gtfs.agency.size() == 0) { - timeZone = ZoneId.of("GMT"); - LOG.warn("graph contains no agencies; API request times will be interpreted as GMT."); - } else { - for (Agency agency : gtfs.agency.values()) { - if (agency.agency_timezone == null) { - LOG.warn("Agency {} is without timezone", agency.agency_name); - continue; - } - ZoneId tz; - try { - tz = ZoneId.of(agency.agency_timezone); - } catch (ZoneRulesException z) { - LOG.error("Agency {} in GTFS with timezone '{}' wasn't found in timezone database reason: {}", agency.agency_name, agency.agency_timezone, z.getMessage()); - //timezone will be set to GMT if it is still empty after for loop - continue; - } catch (DateTimeException dt) { - LOG.error("Agency {} in GTFS has timezone in wrong format:'{}'. Expected format: area/city ", agency.agency_name, agency.agency_timezone); - //timezone will be set to GMT if it is still empty after for loop - continue; - } - //First time setting timezone - if (timeZone == null) { - LOG.info("TransportNetwork time zone set to {} from agency '{}' and agency_timezone:{}", tz, - agency.agency_name, agency.agency_timezone); - timeZone = tz; - } else if (!timeZone.equals(tz)) { - LOG.error("agency time zone {} differs from TransportNetwork time zone: {}. This will be problematic.", tz, - timeZone); - } - } - - //This can only happen if all agencies have empty timezones - if (timeZone == null) { - timeZone = ZoneId.of("GMT"); - LOG.warn( - "No agency in graph had valid timezone; API request times will be interpreted as GMT."); - } - } - - if (level == TransitLayer.LoadLevel.FULL) { - this.fares = new HashMap<>(gtfs.fares); - } - - // Will be useful in naming patterns. -// LOG.info("Finding topology of each route/direction..."); -// Multimap, TripPattern> patternsForRouteDirection = HashMultimap.create(); -// tripPatterns.forEach(tp -> patternsForRouteDirection.put(new T2(tp.routeId, tp.directionId), tp)); -// for (T2 routeAndDirection : patternsForRouteDirection.keySet()) { -// RouteTopology topology = new RouteTopology(routeAndDirection.first, routeAndDirection.second, patternsForRouteDirection.get(routeAndDirection)); -// } - - } - - // The median of all stopTimes would be best but that involves sorting a huge list of numbers. - // So we just use the mean of all stops for now. - private void findCenter (Collection stops) { - double lonSum = 0; - double latSum = 0; - for (Stop stop : stops) { - latSum += stop.stop_lat; - lonSum += stop.stop_lon; - } - // Stops is a HashMap so size() is fast. If it ever becomes a MapDB BTree, we may want to do this differently. - centerLat = latSum / stops.size(); - centerLon = lonSum / stops.size(); - } -} diff --git a/r-package/DESCRIPTION b/r-package/DESCRIPTION index d6b82ff89..56fae64ea 100644 --- a/r-package/DESCRIPTION +++ b/r-package/DESCRIPTION @@ -73,10 +73,12 @@ Suggests: patchwork, rJavaEnv, rmarkdown, - testthat + testthat, + devtools VignetteBuilder: knitr Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.3 SystemRequirements: Java JDK (>= 21.0) +Biarch: true diff --git a/r-package/configure b/r-package/configure new file mode 100755 index 000000000..61cb609fc --- /dev/null +++ b/r-package/configure @@ -0,0 +1,7 @@ +#!/usr/bin/env sh +set -x + +( + cd java + ./gradlew build +) \ No newline at end of file diff --git a/r-package/configure.win b/r-package/configure.win new file mode 100644 index 000000000..9cff6ed2c --- /dev/null +++ b/r-package/configure.win @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +sh ./configure \ No newline at end of file diff --git a/r-package/inst/jar/.gitkeep b/r-package/inst/jar/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/r-package/inst/jar/r5r.jar b/r-package/inst/jar/r5r.jar deleted file mode 100644 index b10e50582..000000000 Binary files a/r-package/inst/jar/r5r.jar and /dev/null differ diff --git a/java-r5rcore/.gitignore b/r-package/java/.gitignore similarity index 100% rename from java-r5rcore/.gitignore rename to r-package/java/.gitignore diff --git a/java-r5rcore/.idea/artifacts/r5r_1_1_0_jar.xml b/r-package/java/.idea/artifacts/r5r_1_1_0_jar.xml similarity index 100% rename from java-r5rcore/.idea/artifacts/r5r_1_1_0_jar.xml rename to r-package/java/.idea/artifacts/r5r_1_1_0_jar.xml diff --git a/java-r5rcore/.idea/misc.xml b/r-package/java/.idea/misc.xml similarity index 100% rename from java-r5rcore/.idea/misc.xml rename to r-package/java/.idea/misc.xml diff --git a/r-package/java/README b/r-package/java/README deleted file mode 100644 index 7abfa6f7a..000000000 --- a/r-package/java/README +++ /dev/null @@ -1,2 +0,0 @@ -Make CRAN quiet about: - Package has FOSS license, installs .class/.jar but has no 'java' directory. \ No newline at end of file diff --git a/java-r5rcore/build.gradle b/r-package/java/build.gradle similarity index 79% rename from java-r5rcore/build.gradle rename to r-package/java/build.gradle index aa6051c93..4fb452ac8 100644 --- a/java-r5rcore/build.gradle +++ b/r-package/java/build.gradle @@ -5,6 +5,8 @@ plugins { tasks.withType(Jar).configureEach { preserveFileTimestamps = false reproducibleFileOrder = true + archiveFileName.set("r5r.jar") + destinationDirectory.set(file("../inst/jar")) } group 'org.ipea' @@ -14,7 +16,7 @@ version '1.1.0999-SNAPSHOT' // grab def baos = new ByteArrayOutputStream() exec { - commandLine 'R', '--no-save', '-q', '-s', '-e', 'setwd("../r-package"); devtools::load_all(quiet=T); cat(download_r5());' + commandLine 'R', '--no-save', '-q', '-s', '-e', 'setwd(".."); devtools::load_all(quiet=T); cat(download_r5());' standardOutput = baos } def r5Path = baos.toString() diff --git a/java-r5rcore/gradle/wrapper/gradle-wrapper.jar b/r-package/java/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from java-r5rcore/gradle/wrapper/gradle-wrapper.jar rename to r-package/java/gradle/wrapper/gradle-wrapper.jar diff --git a/java-r5rcore/gradle/wrapper/gradle-wrapper.properties b/r-package/java/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from java-r5rcore/gradle/wrapper/gradle-wrapper.properties rename to r-package/java/gradle/wrapper/gradle-wrapper.properties diff --git a/java-r5rcore/gradlew b/r-package/java/gradlew similarity index 100% rename from java-r5rcore/gradlew rename to r-package/java/gradlew diff --git a/java-r5rcore/gradlew.bat b/r-package/java/gradlew.bat similarity index 100% rename from java-r5rcore/gradlew.bat rename to r-package/java/gradlew.bat diff --git a/java-r5rcore/src/main/resources/logback.xml b/r-package/java/src/main/resources/logback.xml similarity index 100% rename from java-r5rcore/src/main/resources/logback.xml rename to r-package/java/src/main/resources/logback.xml diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/FarePerRoute.java b/r-package/java/src/org/ipea/r5r/Fares/FarePerRoute.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/FarePerRoute.java rename to r-package/java/src/org/ipea/r5r/Fares/FarePerRoute.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/FarePerTransfer.java b/r-package/java/src/org/ipea/r5r/Fares/FarePerTransfer.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/FarePerTransfer.java rename to r-package/java/src/org/ipea/r5r/Fares/FarePerTransfer.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/FarePerType.java b/r-package/java/src/org/ipea/r5r/Fares/FarePerType.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/FarePerType.java rename to r-package/java/src/org/ipea/r5r/Fares/FarePerType.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/FareStructure.java b/r-package/java/src/org/ipea/r5r/Fares/FareStructure.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/FareStructure.java rename to r-package/java/src/org/ipea/r5r/Fares/FareStructure.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/FareStructureBuilder.java b/r-package/java/src/org/ipea/r5r/Fares/FareStructureBuilder.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/FareStructureBuilder.java rename to r-package/java/src/org/ipea/r5r/Fares/FareStructureBuilder.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/IntegratedFare.java b/r-package/java/src/org/ipea/r5r/Fares/IntegratedFare.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/IntegratedFare.java rename to r-package/java/src/org/ipea/r5r/Fares/IntegratedFare.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/R5RTransferAllowance.java b/r-package/java/src/org/ipea/r5r/Fares/R5RTransferAllowance.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/R5RTransferAllowance.java rename to r-package/java/src/org/ipea/r5r/Fares/R5RTransferAllowance.java diff --git a/java-r5rcore/src/org/ipea/r5r/Fares/RuleBasedInRoutingFareCalculator.java b/r-package/java/src/org/ipea/r5r/Fares/RuleBasedInRoutingFareCalculator.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Fares/RuleBasedInRoutingFareCalculator.java rename to r-package/java/src/org/ipea/r5r/Fares/RuleBasedInRoutingFareCalculator.java diff --git a/java-r5rcore/src/org/ipea/r5r/JsonUtil.java b/r-package/java/src/org/ipea/r5r/JsonUtil.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/JsonUtil.java rename to r-package/java/src/org/ipea/r5r/JsonUtil.java diff --git a/java-r5rcore/src/org/ipea/r5r/Modifications/R5RFileStorage.java b/r-package/java/src/org/ipea/r5r/Modifications/R5RFileStorage.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Modifications/R5RFileStorage.java rename to r-package/java/src/org/ipea/r5r/Modifications/R5RFileStorage.java diff --git a/java-r5rcore/src/org/ipea/r5r/Network/NetworkBuilder.java b/r-package/java/src/org/ipea/r5r/Network/NetworkBuilder.java similarity index 82% rename from java-r5rcore/src/org/ipea/r5r/Network/NetworkBuilder.java rename to r-package/java/src/org/ipea/r5r/Network/NetworkBuilder.java index 5d0631cd8..79e3729e4 100644 --- a/java-r5rcore/src/org/ipea/r5r/Network/NetworkBuilder.java +++ b/r-package/java/src/org/ipea/r5r/Network/NetworkBuilder.java @@ -7,7 +7,10 @@ import com.conveyal.r5.kryo.KryoNetworkSerializer; import com.conveyal.r5.streets.StreetLayer; import com.conveyal.r5.transit.TransferFinder; +import com.conveyal.r5.transit.TransitLayer; import com.conveyal.r5.transit.TransportNetwork; +import com.conveyal.r5.transit.GtfsTransferLoader; +import com.conveyal.r5.analyst.cluster.TransportNetworkConfig.TransferConfig; import org.apache.commons.io.FilenameUtils; import org.ipea.r5r.R5RCore; @@ -116,21 +119,32 @@ private static TransportNetwork createNetwork() { network.streetLayer.parentNetwork = network; network.streetLayer.indexStreets(); - network.transitLayer = new TransitLayerWithShapes(); + network.transitLayer = new TransitLayer(); + // this replaces the old r5r TransitLayerWithShapes class; saving shapes now built in to r5. + network.transitLayer.saveShapes = true; + + // Options here are OSM_ONLY (only use OSM data to find transfers, consistent with r5r versions + // up to 2.3.0), STOP_TO_PATTERN (only use OSM data to find transfers to stops served by patterns + // that do not have a stop with an explicit transfer from the source stop), STOP_TO_STOP (use OSM + // to find transfers for all stop pairs that don't have an explicit GTFS transfer), and GTFS_ONLY + // (use only transfers specified in GTFS, almost never appropriate). + GtfsTransferLoader transferLoader = new GtfsTransferLoader(network.transitLayer, TransferConfig.OSM_ONLY); gtfsFeeds.forEach(gtfsFeed -> { - network.transitLayer.loadFromGtfs(gtfsFeed); + network.transitLayer.loadFromGtfs(gtfsFeed, transferLoader); // Is there a reason we can't push this close call down into the loader method? Maybe exception handling? gtfsFeed.close(); }); + transferLoader.logErrors(); + network.transitLayer.parentNetwork = network; network.streetLayer.associateStops(network.transitLayer); network.streetLayer.buildEdgeLists(); network.rebuildTransientIndexes(); - TransferFinder transferFinder = new TransferFinder(network); + TransferFinder transferFinder = new TransferFinder(network, transferLoader); transferFinder.findTransfers(); transferFinder.findParkRideTransfer(); @@ -150,6 +164,7 @@ private static TransportNetwork createNetwork() { } } catch (DataSourceException e) { e.printStackTrace(); + throw new RuntimeException(e); } network.scenarioId = "r5r"; @@ -162,7 +177,11 @@ private static TransportNetwork createNetwork() { network.transitLayer.buildDistanceTables(null); // pre-calculate transfers between transit stops - new TransferFinder(network).findTransfers(); + // TODO mwbc: why is this happening again? It does not happen twice in the R5 + // TransportNetworkCache#buildNetworkFromConfig. I don't want to remove it though due to + // https://github.com/conveyal/r5/issues/991. Maybe we should just move the entire transfer + // finding process here? + new TransferFinder(network, transferLoader).findTransfers(); return network; } diff --git a/java-r5rcore/src/org/ipea/r5r/Network/NetworkChecker.java b/r-package/java/src/org/ipea/r5r/Network/NetworkChecker.java similarity index 98% rename from java-r5rcore/src/org/ipea/r5r/Network/NetworkChecker.java rename to r-package/java/src/org/ipea/r5r/Network/NetworkChecker.java index 57672b3af..e724a5f06 100644 --- a/java-r5rcore/src/org/ipea/r5r/Network/NetworkChecker.java +++ b/r-package/java/src/org/ipea/r5r/Network/NetworkChecker.java @@ -25,7 +25,7 @@ public class NetworkChecker { * This string should be changed to a new value each time the network storage format changes. * I considered using an ISO date string but that could get confusing when seen in filenames. */ - public static final String NETWORK_FORMAT_VERSION = "nv3"; + public static final String NETWORK_FORMAT_VERSION = "nv4"; public static final byte[] HEADER = "R5NETWORK".getBytes(); diff --git a/java-r5rcore/src/org/ipea/r5r/Planner/Trip.java b/r-package/java/src/org/ipea/r5r/Planner/Trip.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Planner/Trip.java rename to r-package/java/src/org/ipea/r5r/Planner/Trip.java diff --git a/java-r5rcore/src/org/ipea/r5r/Planner/TripLeg.java b/r-package/java/src/org/ipea/r5r/Planner/TripLeg.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Planner/TripLeg.java rename to r-package/java/src/org/ipea/r5r/Planner/TripLeg.java diff --git a/java-r5rcore/src/org/ipea/r5r/Planner/TripPlanner.java b/r-package/java/src/org/ipea/r5r/Planner/TripPlanner.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Planner/TripPlanner.java rename to r-package/java/src/org/ipea/r5r/Planner/TripPlanner.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/AccessibilityEstimator.java b/r-package/java/src/org/ipea/r5r/Process/AccessibilityEstimator.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/AccessibilityEstimator.java rename to r-package/java/src/org/ipea/r5r/Process/AccessibilityEstimator.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/DetailedItineraryPlanner.java b/r-package/java/src/org/ipea/r5r/Process/DetailedItineraryPlanner.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/DetailedItineraryPlanner.java rename to r-package/java/src/org/ipea/r5r/Process/DetailedItineraryPlanner.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/FaretoDebug.java b/r-package/java/src/org/ipea/r5r/Process/FaretoDebug.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/FaretoDebug.java rename to r-package/java/src/org/ipea/r5r/Process/FaretoDebug.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/FastDetailedItineraryPlanner.java b/r-package/java/src/org/ipea/r5r/Process/FastDetailedItineraryPlanner.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/FastDetailedItineraryPlanner.java rename to r-package/java/src/org/ipea/r5r/Process/FastDetailedItineraryPlanner.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/ParetoFrontierCalculator.java b/r-package/java/src/org/ipea/r5r/Process/ParetoFrontierCalculator.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/ParetoFrontierCalculator.java rename to r-package/java/src/org/ipea/r5r/Process/ParetoFrontierCalculator.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/ParetoItineraryPlanner.java b/r-package/java/src/org/ipea/r5r/Process/ParetoItineraryPlanner.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/ParetoItineraryPlanner.java rename to r-package/java/src/org/ipea/r5r/Process/ParetoItineraryPlanner.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/PathOptionsTable.java b/r-package/java/src/org/ipea/r5r/Process/PathOptionsTable.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/PathOptionsTable.java rename to r-package/java/src/org/ipea/r5r/Process/PathOptionsTable.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/R5DataFrameProcess.jav b/r-package/java/src/org/ipea/r5r/Process/R5DataFrameProcess.jav similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/R5DataFrameProcess.jav rename to r-package/java/src/org/ipea/r5r/Process/R5DataFrameProcess.jav diff --git a/java-r5rcore/src/org/ipea/r5r/Process/R5DataFrameProcess.java b/r-package/java/src/org/ipea/r5r/Process/R5DataFrameProcess.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/R5DataFrameProcess.java rename to r-package/java/src/org/ipea/r5r/Process/R5DataFrameProcess.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/R5Process.java b/r-package/java/src/org/ipea/r5r/Process/R5Process.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/R5Process.java rename to r-package/java/src/org/ipea/r5r/Process/R5Process.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/RegularGridProcess.java b/r-package/java/src/org/ipea/r5r/Process/RegularGridProcess.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/RegularGridProcess.java rename to r-package/java/src/org/ipea/r5r/Process/RegularGridProcess.java diff --git a/java-r5rcore/src/org/ipea/r5r/Process/TravelTimeMatrixComputer.java b/r-package/java/src/org/ipea/r5r/Process/TravelTimeMatrixComputer.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Process/TravelTimeMatrixComputer.java rename to r-package/java/src/org/ipea/r5r/Process/TravelTimeMatrixComputer.java diff --git a/java-r5rcore/src/org/ipea/r5r/R5/R5ParetoServer.java b/r-package/java/src/org/ipea/r5r/R5/R5ParetoServer.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/R5/R5ParetoServer.java rename to r-package/java/src/org/ipea/r5r/R5/R5ParetoServer.java diff --git a/java-r5rcore/src/org/ipea/r5r/R5/R5TravelTimeComputer.java b/r-package/java/src/org/ipea/r5r/R5/R5TravelTimeComputer.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/R5/R5TravelTimeComputer.java rename to r-package/java/src/org/ipea/r5r/R5/R5TravelTimeComputer.java diff --git a/java-r5rcore/src/org/ipea/r5r/R5RCore.java b/r-package/java/src/org/ipea/r5r/R5RCore.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/R5RCore.java rename to r-package/java/src/org/ipea/r5r/R5RCore.java diff --git a/java-r5rcore/src/org/ipea/r5r/RDataFrame.java b/r-package/java/src/org/ipea/r5r/RDataFrame.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/RDataFrame.java rename to r-package/java/src/org/ipea/r5r/RDataFrame.java diff --git a/java-r5rcore/src/org/ipea/r5r/RegularGridResult.java b/r-package/java/src/org/ipea/r5r/RegularGridResult.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/RegularGridResult.java rename to r-package/java/src/org/ipea/r5r/RegularGridResult.java diff --git a/java-r5rcore/src/org/ipea/r5r/RoutingProperties.java b/r-package/java/src/org/ipea/r5r/RoutingProperties.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/RoutingProperties.java rename to r-package/java/src/org/ipea/r5r/RoutingProperties.java diff --git a/java-r5rcore/src/org/ipea/r5r/Scenario/DummyScenario.java b/r-package/java/src/org/ipea/r5r/Scenario/DummyScenario.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Scenario/DummyScenario.java rename to r-package/java/src/org/ipea/r5r/Scenario/DummyScenario.java diff --git a/java-r5rcore/src/org/ipea/r5r/Scenario/R5RShapefileLts.java b/r-package/java/src/org/ipea/r5r/Scenario/R5RShapefileLts.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Scenario/R5RShapefileLts.java rename to r-package/java/src/org/ipea/r5r/Scenario/R5RShapefileLts.java diff --git a/java-r5rcore/src/org/ipea/r5r/Scenario/R5RShapefileMatcher.java b/r-package/java/src/org/ipea/r5r/Scenario/R5RShapefileMatcher.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Scenario/R5RShapefileMatcher.java rename to r-package/java/src/org/ipea/r5r/Scenario/R5RShapefileMatcher.java diff --git a/java-r5rcore/src/org/ipea/r5r/Scenario/RoadCongestionOSM.java b/r-package/java/src/org/ipea/r5r/Scenario/RoadCongestionOSM.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Scenario/RoadCongestionOSM.java rename to r-package/java/src/org/ipea/r5r/Scenario/RoadCongestionOSM.java diff --git a/java-r5rcore/src/org/ipea/r5r/Scenario/SetLtsOsm.java b/r-package/java/src/org/ipea/r5r/Scenario/SetLtsOsm.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Scenario/SetLtsOsm.java rename to r-package/java/src/org/ipea/r5r/Scenario/SetLtsOsm.java diff --git a/java-r5rcore/src/org/ipea/r5r/SnapFinder.java b/r-package/java/src/org/ipea/r5r/SnapFinder.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/SnapFinder.java rename to r-package/java/src/org/ipea/r5r/SnapFinder.java diff --git a/java-r5rcore/src/org/ipea/r5r/StreetNetwork.java b/r-package/java/src/org/ipea/r5r/StreetNetwork.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/StreetNetwork.java rename to r-package/java/src/org/ipea/r5r/StreetNetwork.java diff --git a/java-r5rcore/src/org/ipea/r5r/TransitNetwork.java b/r-package/java/src/org/ipea/r5r/TransitNetwork.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/TransitNetwork.java rename to r-package/java/src/org/ipea/r5r/TransitNetwork.java diff --git a/java-r5rcore/src/org/ipea/r5r/Utils/RMapBuilder.java b/r-package/java/src/org/ipea/r5r/Utils/RMapBuilder.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Utils/RMapBuilder.java rename to r-package/java/src/org/ipea/r5r/Utils/RMapBuilder.java diff --git a/java-r5rcore/src/org/ipea/r5r/Utils/SpeedSetter.java b/r-package/java/src/org/ipea/r5r/Utils/SpeedSetter.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Utils/SpeedSetter.java rename to r-package/java/src/org/ipea/r5r/Utils/SpeedSetter.java diff --git a/java-r5rcore/src/org/ipea/r5r/Utils/Utils.java b/r-package/java/src/org/ipea/r5r/Utils/Utils.java similarity index 100% rename from java-r5rcore/src/org/ipea/r5r/Utils/Utils.java rename to r-package/java/src/org/ipea/r5r/Utils/Utils.java diff --git a/r-package/tests/tests_marcus/fares.R b/r-package/tests/tests_marcus/fares.R index 32fd0e738..0ff54ba61 100644 --- a/r-package/tests/tests_marcus/fares.R +++ b/r-package/tests/tests_marcus/fares.R @@ -1,11 +1,11 @@ library("tidyverse") -fare_schema_df <- read_csv("../java-r5rcore/src/main/resources/fares/rio/fare_schema.csv") -routes_info_df <- read_csv("../java-r5rcore/src/main/resources/fares/rio/routes_info.csv") +fare_schema_df <- read_csv("src/src/main/resources/fares/rio/fare_schema.csv") +routes_info_df <- read_csv("src/src/main/resources/fares/rio/routes_info.csv") modes_prices_df <- routes_info_df %>% select(type, price) %>% distinct() -modes_prices_df %>% write_csv("../java-r5rcore/src/main/resources/fares/rio/price_per_mode.csv") +modes_prices_df %>% write_csv("src/src/main/resources/fares/rio/price_per_mode.csv")