R/otp-setup.R

Defines functions otp_build_graph otp_setup otp_stop otp_checks

Documented in otp_build_graph otp_checks otp_setup otp_stop

#' Build an OTP Graph
#'
#' OTP is run in Java and requires Java commands to be typed into the command line.
#' The function allows the parameters to be defined in R and automatically passed to Java.
#' This function builds a OTP graph from the Open Street Map and other files.
#'
#' @param otp A character string, path to the OTP .jar file
#' @param dir A character string, path to a directory containing the necessary files, see details
#' @param memory A positive integer. Amount of memory to assign to OTP in GB, default is 2
#' @param router A character string for the name of the router, must match with contents of dir, default "current"
#' @param analyst Logical, should analyst feature be built, default FALSE
#' @return
#' Returns and log messages produced by OTP, and will return the message "Graph built" if successful
#' @details
#' The OTP .jar file can be downloaded from https://repo1.maven.org/maven2/org/opentripplanner/otp/
#'
#' To build an OTP graph requires the following files to be in the directory
#' specified by the dir variable.
#'
#' /graphs - A sub-directory
#'   /current - A sub-directory with the name of the OTP router used in 'router' variable
#'     osm.pbf - Required, pbf file containing the Open Street Map
#'     router-config.json - Required, json file containing configuration settings for OTP
#'     gtfs.zip - Optional, and number of GTFS files with transit timetables
#'     terrain.tif - Optional, GeoTiff image of terrain map
#'
#' The function will accept any file name for the .jar file, but it must be the only .jar file in that directory
#' OTP can support multiple routers (e.g. different regions), each router must have its own sub-directory in the graphs directory
#' @examples \dontrun{
#' log = otp_build_graph(otp = "C:/otp/otp.jar", dir = "C:/data")
#'}
#' @export
otp_build_graph <- function(otp = NULL,
                            dir = NULL,
                            memory = 2,
                            router = "current",
                            analyst = FALSE)
{
  # Run Checks
  otp_checks(
    otp = otp,
    dir = dir,
    router = router,
    graph = F
  )
  message("Basic checks completed, building graph, this may take a few minutes")

  # Set up OTP
  text <- paste0('java -Xmx',
                 memory,
                 'G -jar "',
                 otp,
                 '" --build "',
                 dir,
                 '/graphs/',
                 router,
                 '"')

  if (analyst) {
    text <- paste0(text, " --analyst")
  }


  set_up <- try(system(text, intern = TRUE))

  # Check for errors
  if (grepl("ERROR", set_up[2]) | grepl("Error", set_up[1])) {
    message("Failed to build graph with message:")
    message(set_up[2])
  } else{
    message("Graph built")

  }
  return(set_up)


}


#' Set up an OTP instance.
#'
#' OTP is run in Java and requires Java commands to be typed into the command line.
#' The function allows the parameters to be defined in R and automatically passed to Java.
#' This function sets up a local instance of OTP, for remote versions see documentation.
#'
#' The function assumes you have run otp_build_graph()
#' @param otp A character string, path to the OTP .jar file
#' @param dir A character string, path to a directory containing the necessary files, see details
#' @param memory A positive integer. Amount of memory to assign to OTP in GB, default is 2
#' @param router A character vector for the name of the routers, must match with contents of dir, default "current"
#' Only a single router is currently supported
#' @param port A positive integer. Optional, default is 8080.
#' @param securePort A positive integer. Optional, default is 8081.
#' @param analyst Logical. Should the analyst features be loaded? Default FALSE
#' @param wait Logical, Should R wait until OTP has loaded before running next line of code, default TRUE
#' @return
#' This function does not return a value to R.
#' If wait is TRUE R will wait until OTP is running (maximum of 5 minutes)
#' @details
#' To run an OTP graph must have been created using otp_build_graph and the following files to be in the directory
#' specified by the dir variable.
#'
#' /graphs - A sub-directory
#'   /current - A sub-directory with the name of the OTP router used in 'router' variable
#'     graph.obj  OTP graph
#'
#' @examples \dontrun{
#' otp_setup(otp = "C:/otp/otp.jar", dir = "C:/data")
#' otp_setup(otp = "C:/otp/otp.jar", dir = "C:/data", memory = 5, analyst = TRUE)
#' }
#' @export
otp_setup <- function(otp = NULL,
                      dir = NULL,
                      memory = 2,
                      router = "current",
                      port = 8080,
                      securePort = 8081,
                      analyst = FALSE,
                      wait = TRUE)
{
  # Run Checks
  otp_checks(
    otp = otp,
    dir = dir,
    router = router,
    graph = T
  )
  memory <- floor(memory) # Can't have fractions of GB


  # Set up OTP
  if (checkmate::testOS("linux")) {
    message("You're on linux, this function is not yet supported")
    stop()

  } else if (checkmate::testOS("windows")) {
    text <- paste0(
      'java -Xmx',
      memory,
      'G -jar "',
      otp,
      '" --router ',
      router,
      ' --graphs "',
      dir,
      '/graphs"',
      ' --server --port ',
      port,
      ' --securePort ',
      securePort
    )

    if (analyst) {
      text <- paste0(text, " --analyst")
    }
    set_up <- try(system(text, intern = FALSE, wait = FALSE))


  } else if (checkmate::testOS("mac")) {
    message("You're on Mac, this function is not yet supported")
    stop()

  } else{
    message("You're on and unknown OS, this function is not yet supported")
    stop()

  }


  # Check for errors
  if (grepl("ERROR", set_up[2])) {
    message("Failed to start OTP with message:")
    message(set_up[2])
  }

  message(paste0(Sys.time(), " OTP is loading and may take a while to be useable"))

  if (wait) {
    Sys.sleep(30)

    # Check if connected
    for (i in 1:10) {
      #message(paste0("Attempt ",i))
      otpcon <- try(otp_connect(
        hostname = "localhost",
        router = router,
        port = port,
        ssl = FALSE,
        check = TRUE
      ),
      silent = T)

      if ("otpconnect" %in% class(otpcon)) {
        message(
          paste0(
            Sys.time(),
            " OTP is ready to use Go to localhost:",
            port,
            " in your browser to view OTP"
          )
        )
        utils::browseURL(paste0(
          ifelse(otpcon$ssl, "https://", "http://"),
          "localhost:",
          port
        ))
        break
      } else{
        if (i < 10) {
          Sys.sleep(30)
        } else{
          message(
            paste0(
              Sys.time(),
              " OTP is taking an unusually long time to load, releasing R to your control"
            )
          )
        }

      }
    }
  }

}

#' Stop and OTP Instance
#'
#' OTP is run in Java and requires Java commands to be typed into the command line.
#' The function allows the parameters to be defined in R and automatically passed to Java.
#' This function stops an already running OTP instance
#'
#' The function assumes you have run otp_setup()
#'
#' @export
otp_stop <- function()
{
  if (checkmate::testOS("linux")) {
    message("You're on linux, this function is not yet supported")
  } else if (checkmate::testOS("windows")) {
    readline(prompt = "This will force Java to close, Press [enter] to continue, [escape] to abort")
    system("Taskkill /IM java.exe /F", intern = TRUE)
  } else if (checkmate::testOS("mac")) {
    message("You're on Mac, this function is not yet supported")
  } else{
    message("You're on and unknown OS, this function is not yet supported")
  }

}


#' Basic OTP Setup Checks
#'
#' Checks to run before setting up OTP
#'
#' @param dir A character string path to a folder containing the necessary files, see details
#' @param router A character string for the name of the router, must match with contents of dir, default "current"
#' @param graph Logical, check for graph, default = FALSE
#' @param otp Path to otp.jar
#'
otp_checks <-
  function(otp = NULL,
           dir = NULL,
           router = NULL,
           graph = FALSE)
  {
    # Checks
    checkmate::assertFileExists(otp, extension = "jar")
    checkmate::assertDirectoryExists(dir)
    checkmate::assertDirectoryExists(paste0(dir, "/graphs/", router))

    # Check we have correct version of Java
    if (checkmate::testOS("linux")) {
      message("You're on linux, java version check not yet supported")
    } else if (checkmate::testOS("windows")) {
      java_version <- try(system("java -version", intern = TRUE))
      if (class(java_version) == "try-error") {
        warning("R was unable to detect a version of Java")
        stop()
      } else{
        java_version <- java_version[1]
        java_version <- strsplit(java_version, "\"")[[1]][2]
        java_version <- strsplit(java_version, "\\.")[[1]][1:2]
        java_version <-
          as.numeric(paste0(java_version[1], ".", java_version[2]))
        if (is.na(java_version)) {
          warning("OTP requires Java version 8 ")
          stop()
        }
        if (java_version < 1.8 | java_version >= 1.9) {
          warning("OTP requires Java version 8 ")
          stop()
        }
      }
    } else if (checkmate::testOS("mac")) {
      message("You're on Mac, java version check not yet supported")
    } else{
      message("You're on and unknown OS, java version check not yet supported")
    }

    # Check that the graph exists
    if (graph) {
      checkmate::assertFileExists(paste0(dir, "/graphs/", router, "/Graph.obj"))
    }

    ### End of Checks
  }
marcusyoung/opentripplanner documentation built on May 20, 2019, 4:42 p.m.