--- title: "Using Julia and Circuitscape with ResistanceGA2" author: "Bill Peterman" date: "`r format(Sys.Date(), '%d %B %Y')`" output: rmarkdown::html_vignette: toc: true toc_depth: 3 number_sections: true vignette: | %\VignetteIndexEntry{Using Julia and Circuitscape with ResistanceGA2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} julia_bindir <- Sys.getenv("JULIA_BINDIR", unset = "") if (!nzchar(julia_bindir)) { julia_exe <- Sys.which("julia") if (nzchar(julia_exe)) { julia_bindir <- dirname(julia_exe) } } julia_candidates <- file.path(julia_bindir, c("julia", "julia.exe")) has_julia <- nzchar(julia_bindir) && any(file.exists(julia_candidates)) if (has_julia) { JULIA_HOME <- normalizePath(julia_bindir, winslash = "/", mustWork = TRUE) Sys.setenv(JULIA_BINDIR = JULIA_HOME) } else { JULIA_HOME <- "C:/Users/your-name/AppData/Local/Programs/Julia-/bin/" } knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5, message = FALSE, warning = FALSE ) ``` ```{r libraries} library(ResistanceGA2) library(terra) ``` --- # Overview `ResistanceGA2` supports two distance engines: `gdistance` (which runs entirely inside R) and Circuitscape running through Julia (which requires an external Julia installation). This vignette covers everything needed to install, configure, and troubleshoot the Julia/Circuitscape path. **When to use Julia/Circuitscape vs. gdistance:** | Criterion | Julia/Circuitscape | gdistance | |---|---|---| | Output matches Circuitscape | Yes | No | | Current maps | Yes | No | | Speed (iterative optimization) | Slower per call (startup overhead) | Faster per call | | External dependency | Julia + Circuitscape.jl | None | | Random-walk distances | Yes (resistance distance) | Yes (commuteDistance) | | Least-cost path distances | No | Yes (costDistance) | For most iterative optimization workflows, `gdistance::commuteDistance()` is the most convenient choice as it stays inside R, requires no external setup, and produces qualitatively similar distances to Circuitscape resistance distance. Use Julia/Circuitscape when you need to: - Produce output that directly matches a Circuitscape workflow (for comparability with published analyses). - Generate cumulative current maps for visualization or downstream analysis. - Use Circuitscape's cholmod-accelerated solver for very large landscapes. --- # Step 1: Install Julia ## Downloading Julia Download Julia from the official website: Install the **current stable release** (e.g., Julia 1.11.x). Both 64-bit Windows and macOS/Linux installers are available. The default installation location works well; note the installation path because you will need it later. > **Version compatibility.** The R-to-Julia bridge depends on the version of `JuliaConnectoR` you have installed keeping pace with very new Julia releases. If `JuliaConnectoR::juliaEval()` crashes the R session even though `JuliaConnectoR::juliaSetupOk()` returns `TRUE`, the most likely cause is a mismatch between a bleeding-edge Julia release and an older `JuliaConnectoR`. In that case, update `JuliaConnectoR` to its latest version, or install a Julia release one minor version behind the newest. A combination known to work for the package developer should be preferred over the absolute newest Julia. > **Windows users.** Do not rely on the `julia` command installed through the Microsoft Store app alias. That stub can report a version with `julia --version` yet fail to launch a working session for `JuliaConnectoR` (you may see an error about a missing `sys.dll`). Install Julia from the official downloads page above and point `JULIA_HOME` at that installation's `bin/` directory. **Default installation paths by platform:** - **Windows:** `C:\Users\\AppData\Local\Programs\Julia-X.Y.Z\` - **macOS:** `/Applications/Julia-X.Y.app/Contents/Resources/julia/` - **Linux:** Wherever you extracted the tarball, typically `/opt/julia-X.Y.Z/` The Julia binary directory (`bin/`) is one level inside the installation root. For example, on Windows: `C:\Users\\AppData\Local\Programs\Julia-\bin\` ## Verifying the Julia Installation Open a terminal (Command Prompt, PowerShell, or bash) and run: ```bash julia --version ``` You should see output like `julia version 1.x.y`. If the command is not found, Julia's `bin/` directory is not on your PATH. You may need to add it manually, or just supply the full path when configuring `ResistanceGA2`. --- # Step 2: Install Circuitscape.jl Open Julia (type `julia` at the terminal prompt, or open the Julia application) and install the Circuitscape package: ```julia using Pkg Pkg.add("Circuitscape") Pkg.test("Circuitscape") ``` The installation will download Circuitscape and its dependencies. The test suite confirms the installation is working correctly. This step only needs to be done once per Julia environment. > **Note:** Julia has a package manager that maintains environments similar to R's `renv` or Python's `venv`. By default, packages you install from the Julia REPL go into the default environment (`@v1.11` for Julia 1.11). When `ResistanceGA2` launches Julia via `JuliaConnectoR`, it uses this same default environment. If you later switch Julia versions, you will need to install Circuitscape again in the new version's default environment. ## Installing JuliaConnectoR `ResistanceGA2` uses `JuliaConnectoR` as its R-to-Julia bridge. This replaces the `JuliaCall` package used in the original `ResistanceGA`. If your scripts call `JuliaCall` functions directly, update them to the `JuliaConnectoR` equivalents. Install the `JuliaConnectoR` R package: ```{r install-juliaconnector, eval=FALSE} install.packages("JuliaConnectoR") ``` --- # Step 3: Configure R to Find Julia `ResistanceGA2` needs to know where Julia's `bin/` directory is. Set this before calling any Julia-related functions: ```{r julia-home, eval=FALSE} # Replace with the installed Julia version. JULIA_HOME <- "C:/Users/your-name/AppData/Local/Programs/Julia-/bin/" Sys.setenv(JULIA_BINDIR = JULIA_HOME) ``` ```{r julia-home-run, include=FALSE} # JULIA_HOME is initialized in the setup chunk. When Julia is not available # during vignette rendering, it falls back to an example path for display only. ``` To avoid setting this every session, add the `Sys.setenv()` line to your `.Rprofile`: ```{r rprofile, eval=FALSE} # Add to ~/.Rprofile (or project-level .Rprofile): Sys.setenv(JULIA_BINDIR = "C:/Users/your-name/AppData/Local/Programs/Julia-/bin/") ``` > **Note:** On Windows, use forward slashes (`/`) in path strings in R, even though Windows normally uses backslashes. `JuliaConnectoR` and `ResistanceGA2` normalize paths internally, but using forward slashes avoids escape-sequence issues. ## How ResistanceGA2 Manages Julia Paths The Julia-facing helpers in `ResistanceGA2` are designed to keep your R session stable while still making Julia configuration explicit. You can either set `JULIA_BINDIR` once for the whole session, or pass the same path as `JULIA_HOME` to `jl.prep()`, `Run_CS.jl()`, or `Run_CS.ini()`. When you pass `JULIA_HOME`, the package temporarily points `JuliaConnectoR` to that Julia `bin/` directory and restores the previous `JULIA_BINDIR` value when the function exits. This matters when you work on a machine with multiple Julia versions, or when a project should use a specific Julia installation without leaving your global R session changed. ```{r julia-helper-path-demo, eval=FALSE} # Record the session state before configuring the ResistanceGA2 Julia backend. old_bindir <- Sys.getenv("JULIA_BINDIR", unset = NA_character_) JULIA_HOME <- "C:/Users/your-name/AppData/Local/Programs/Julia-/bin/" jl_inputs <- jl.prep( n.Pops = nrow(samples), response = lower(as.matrix(dist(samples[, 2:3]))), CS_Point.File = terra::vect(samples[, 2:3], type = "points"), JULIA_HOME = JULIA_HOME, run_test = FALSE ) # The package restores the previous value after jl.prep() returns. identical(Sys.getenv("JULIA_BINDIR", unset = NA_character_), old_bindir) ``` `ResistanceGA2` also loads `Circuitscape.jl` once per R session and Julia `bin/` path. The first call to `jl.prep()`, `Run_CS.jl()`, or `Run_CS.ini()` may still pay the Julia startup cost, but later calls with the same `JULIA_HOME` reuse the loaded Julia session. **How to read this setup:** `JULIA_HOME` is a project-level choice. It tells the package which Julia installation should run Circuitscape. `JULIA_BINDIR` is the environment variable used by `JuliaConnectoR` internally. In normal `ResistanceGA2` workflows, pass `JULIA_HOME` to the package function and let the helper manage `JULIA_BINDIR` for that call. ## Finding Julia's Path Automatically If Julia is on your system PATH, you can find the `bin/` directory from R: ```{r find-julia, eval=FALSE} # Find Julia on PATH julia_exe <- Sys.which("julia") if (nzchar(julia_exe)) { JULIA_HOME <- dirname(julia_exe) message("Found Julia at: ", JULIA_HOME) } else { message("Julia not found on PATH. Set JULIA_BINDIR manually.") } ``` --- # Step 4: Verify the Connection After setting `JULIA_BINDIR`, verify that R can start Julia and load Circuitscape: ```{r verify-julia, eval=FALSE} Sys.setenv(JULIA_BINDIR = JULIA_HOME) # This triggers Julia startup on first call JuliaConnectoR::juliaEval("string(VERSION)") ``` ```{r verify-circuitscape, eval=FALSE} # Confirm Circuitscape is available JuliaConnectoR::juliaEval("using Circuitscape") ``` These verification chunks are shown for copy-paste use but are not executed during vignette builds. Run them manually in your own R session after setting `JULIA_BINDIR`. If both commands succeed without error, your Julia/Circuitscape setup is ready for `ResistanceGA2`. --- # Step 5: Prepare a Small Julia Example ## Set Up Sample Data ```{r small-example} pts <- vect(samples[, 2:3], type = "points") surfaces <- terra::unwrap(resistance_surfaces) surface <- terra::subset(surfaces, "continuous") pts surface ``` ## Create Julia Inputs with jl.prep() `jl.prep()` configures everything needed for Circuitscape runs. Setting `run_test = TRUE` is strongly recommended the first time you use the package on a new machine; it runs a small Circuitscape test to verify the full pipeline before a long optimization: ```{r jl-prep, eval=FALSE} pairwise_genetic <- lower(as.matrix(dist(samples[, 2:3]))) jl_inputs <- jl.prep( n.Pops = nrow(samples), response = pairwise_genetic, CS_Point.File = pts, JULIA_HOME = JULIA_HOME, run_test = TRUE, # verify the connection silent = TRUE # suppress Julia startup messages ) names(jl_inputs) ``` ### jl.prep() Parameter Details | Parameter | Default | Description | |---|---|---| | `n.Pops` | required | Number of sample populations | | `response` | NULL | Pairwise genetic distances (vector from `lower()`) | | `CS_Point.File` | required | `SpatVector` of sample point locations | | `JULIA_HOME` | required | Path to Julia `bin/` directory | | `run_test` | FALSE | Run a test Circuitscape calculation to verify setup | | `silent` | FALSE | Suppress Julia startup messages | | `cholmod` | TRUE | Use CHOLMOD direct solver (faster, more memory) | | `precision` | FALSE | Use single precision (saves memory for large landscapes) | | `scratch` | NULL | Temporary file directory (use if default tmpdir is slow) | | `rm.files` | TRUE | Remove intermediate files after each run | **Solver selection guidance:** - `cholmod = TRUE` (default): Uses the CHOLMOD Cholesky factorization. Fastest option but can require substantial memory for large rasters. Start here. - `cholmod = FALSE` (iterative): Falls back to iterative methods. Slower but uses less peak memory. Try this if CHOLMOD runs out of memory. - `precision = TRUE`: Uses single-precision arithmetic, roughly halving memory use. Slightly less accurate but acceptable for most landscape genetics analyses. --- # Computing Pairwise Resistance Distances ## Run_CS.jl() for Pairwise Distances In this workflow, `Run_CS.jl(..., output = "matrix")` returns a lower-triangle vector of pairwise resistance distances, ordered the same way as other `ResistanceGA2` pairwise outputs. That is why the result is indexed like a vector, not like a 2-D matrix. ```{r run-circuitscape, eval=FALSE} cs_vector <- Run_CS.jl( jl.inputs = jl_inputs, r = surface, output = "matrix" ) length(cs_vector) head(cs_vector) ``` The precomputed example for the small dataset ships with the package: ```{r precomputed-cs} cs_vector <- vignette_pairwise_outputs$circuitscape_matrix length(cs_vector) head(cs_vector) ``` ## Run_CS.jl() Parameter Details ## Direct Circuitscape runs with `.ini`-style control If you want fuller control over Circuitscape options than `Run_CS.jl()` is designed to expose, use `Run_CS.ini()`. ```{r run-cs-ini, eval=FALSE} cs_out <- Run_CS.ini( r = surface, CS_Point.File = pts, JULIA_HOME = JULIA_HOME, scenario = "pairwise", connect_four_neighbors_only = TRUE, write_cur_maps = TRUE, write_cum_cur_map_only = TRUE, return = "all", rm.files = FALSE ) ``` See the separate `Direct Circuitscape Runs from R` vignette for examples using advanced mode, source and ground inputs, included-pairs files, and other Circuitscape support files. ## Current maps | Parameter | Default | Description | |---|---|---| | `jl.inputs` | required | Output of `jl.prep()` | | `r` | required | `SpatRaster` resistance surface | | `CurrentMap` | FALSE | Compute cumulative current map in addition to pairwise distances | | `output` | `"matrix"` | `"matrix"` for pairwise distances; `"raster"` for current map | | `EXPORT.dir` | NULL | Directory for output files when `output = "raster"` | | `rm.files` | TRUE | Remove temporary files after run | | `write.files` | FALSE | Write output files even when temporary | | `write.criteria` | NULL | Only write files when LL exceeds this threshold | --- # Computing Current Maps Current maps show the cumulative flow of "current" across the entire landscape between all pairs of source nodes. They are useful for identifying high-connectivity corridors, bottlenecks, and pinch points. ```{r run-current-map, eval=FALSE} export_dir <- file.path(tempdir(), "ResistanceGA2-current-map") current_map <- Run_CS.jl( jl.inputs = jl_inputs, r = surface, CurrentMap = TRUE, output = "raster", EXPORT.dir = export_dir ) plot(current_map, main = "Cumulative current map") ``` The package ships a precomputed current map for the small example: ```{r precomputed-current-map} plot(vignette_current_map) ``` --- # Julia in Optimization Workflows Once `jl_inputs` is ready, the optimization workflow is identical to the `gdistance` workflow: simply pass `jl.inputs` instead of `gdist.inputs`: ```{r julia-optim, eval=FALSE} GA.inputs <- GA.prep( raster = terra::subset(terra::unwrap(resistance_surfaces), "continuous"), Results.dir = file.path(tempdir(), "ResistanceGA2-julia"), pop.size = 25, maxiter = 200, run = 25, monitor = FALSE, quiet = TRUE ) ss_out <- SS_optim( jl.inputs = jl_inputs, GA.inputs = GA.inputs, dist_mod = FALSE, null_mod = FALSE, diagnostic_plots = FALSE ) ``` These optimization outputs are now S3 objects, so routine inspection is cleaner than before. ```{r julia-s3-ss, eval=FALSE} class(ss_out) summary(ss_out) plot(ss_out, type = "response") plot(ss_out, type = "ranking") ``` For multiple surfaces: ```{r julia-ms, eval=FALSE} GA.inputs_multi <- GA.prep( raster = terra::subset( terra::unwrap(resistance_surfaces), c("categorical", "continuous") ), Results.dir = file.path(tempdir(), "ResistanceGA2-julia-multi"), pop.size = 25, maxiter = 200, run = 25, monitor = FALSE, quiet = TRUE ) ms_out <- MS_optim( jl.inputs = jl_inputs, GA.inputs = GA.inputs_multi, diagnostic_plots = FALSE ) ``` > **Note:** During optimization, `ResistanceGA2` automatically suppresses the verbose `@info` and `@warn` output that Circuitscape.jl prints to the console. You will not see per-call messages from Julia during `SS_optim()`, `MS_optim()`, or `all_comb()` runs. Set `silent = TRUE` in `jl.prep()` to also suppress Julia startup messages during the initial connection test. > **Tip:** During optimization, `ResistanceGA2` calls `Run_CS.jl()` hundreds or thousands of times (once per candidate solution per generation). Julia's startup overhead is paid only once when `JuliaConnectoR` first connects; subsequent calls are much faster. However, file I/O for the intermediate Circuitscape inputs and outputs still occurs each call. Setting `rm.files = TRUE` (the default) keeps the temporary directory clean and avoids accumulating large numbers of files. ```{r julia-s3-ms, eval=FALSE} class(ms_out) summary(ms_out) plot(ms_out, type = "response") plot(ms_out, type = "contribution") ``` # Tuning and Troubleshooting --- # Comparing gdistance and Julia Outputs ## Conceptual Similarity Both `gdistance::commuteDistance()` and Circuitscape compute random-walk based effective distances. They are derived from the same mathematical framework (circuit theory / random walk theory) and should produce highly correlated outputs on the same resistance surface. In practice, the outputs are not identical because: 1. `commuteDistance()` uses a graph-based representation where only adjacent cells are connected, while Circuitscape models current flow through the full grid using finite element methods. 2. `commuteDistance()` uses 4-neighbor or 8-neighbor connectivity; Circuitscape uses 4-neighbor by default. 3. Numerical precision and solver differences introduce small discrepancies. The two distance measures will typically be very highly correlated (r > 0.95) for the same resistance surface, but the absolute values will differ in scale. ## Comparing Outputs ```{r compare-outputs, eval=FALSE} # Compute both distance types from the same surface gdist_inputs <- gdist.prep( n.Pops = nrow(samples), samples = terra::vect(samples[, 2:3], type = "points"), method = "commuteDistance" ) gdist_out <- Run_gdistance( gdist.inputs = gdist_inputs, r = terra::subset(terra::unwrap(resistance_surfaces), "continuous") ) # These will be on different scales but should be highly correlated gdist_vec <- lower(as.matrix(gdist_out)) cs_vec <- vignette_pairwise_outputs$circuitscape_matrix cor(gdist_vec, cs_vec) # Visual comparison plot(gdist_vec, cs_vec, xlab = "gdistance commuteDistance", ylab = "Circuitscape resistance distance", main = "Comparison of distance engines") ``` The high correlation means that optimization results (which surface is best, what parameters are recovered) are typically very similar between the two engines. **The choice of distance engine should be driven by what you need from the output** (Circuitscape-matched values, current maps, etc.), not by expectation of meaningfully different optimization results. --- # Performance Considerations ## Landscape Size Circuitscape computational cost scales approximately with the number of non-null cells in the resistance raster. Larger landscapes take longer. | Raster size (cells) | Approximate runtime per call | Notes | |---|---|---| | < 50,000 | < 1 second | Negligible overhead | | 50,000 – 500,000 | 1–30 seconds | Optimization may be slow | | > 500,000 | 30+ seconds | Consider aggregating raster | | > 2,000,000 | Minutes per call | Impractical for iterative optimization | For large landscapes, consider: 1. **Aggregating the raster** to a coarser resolution for optimization, then resampling the optimal surface back to fine resolution for current map generation. 2. **Using `gdistance`** for the iterative optimization step, then running Circuitscape once with the optimal parameters for final output. 3. **Using `precision = TRUE`** to reduce memory use. 4. **Using `cholmod = FALSE`** if CHOLMOD runs out of memory. ## Number of Populations Circuitscape runtime also scales with the number of source nodes (sample populations). For n populations, there are n*(n-1)/2 pairwise computations. | n populations | Pairwise observations | Typical overhead per call | |---|---|---| | 10 | 45 | Minimal | | 20 | 190 | Moderate | | 50 | 1225 | Substantial | | 100 | 4950 | Consider gdistance instead | For datasets with many populations on large landscapes, `gdistance` will usually be substantially faster for optimization. Use Circuitscape for the final output only. `recommend_commute_settings()` can help with that handoff. A common pattern is: ```{r julia-gdistance-handoff, eval=FALSE} commute_plan <- recommend_commute_settings( raster = terra::subset(terra::unwrap(resistance_surfaces), "continuous"), n.Pops = nrow(samples) ) gdist_inputs <- gdist.prep( n.Pops = nrow(samples), response = lower(as.matrix(dist(samples[, 2:3]))), samples = terra::vect(samples[, 2:3], type = "points"), method = "commuteDistance", commute.approx = commute_plan$commute.approx, approx.factor = commute_plan$approx.factor ) # Use gdist_inputs during GA optimization, then run the final best surface with # jl.prep() / Run_CS.jl() if you need Circuitscape-matched output or a current map. ``` --- # Environment Management for Julia Packages Julia uses a built-in package manager (Pkg) that stores package versions in environment manifests. The key environment for `ResistanceGA2` is the **default environment** for the Julia version you're using. ## Checking Your Julia Environment From the Julia REPL: ```julia using Pkg Pkg.status() ``` This shows all packages installed in the current environment. You should see `Circuitscape` listed. ## Multiple Julia Versions If you have multiple Julia versions installed, make sure `JULIA_HOME` points to the one where you installed `Circuitscape.jl`. Different Julia versions have separate environments. ```{r multiple-julia, eval=FALSE} # Check which Julia version JuliaConnectoR is using JuliaConnectoR::juliaEval("string(VERSION)") # If wrong, update JULIA_HOME and restart R Sys.setenv(JULIA_BINDIR = "/path/to/correct/julia/bin/") ``` ## Updating Circuitscape.jl To update Circuitscape to the latest version, run from the Julia REPL: ```julia using Pkg Pkg.update("Circuitscape") ``` After updating, test the new version before running a large optimization: ```{r test-after-update, eval=FALSE} jl_inputs_test <- jl.prep( n.Pops = nrow(samples), CS_Point.File = vect(samples[, 2:3], type = "points"), JULIA_HOME = JULIA_HOME, run_test = TRUE ) ``` --- # Troubleshooting ## Julia Not Found **Symptom:** Error: "Could not find Julia" or "JULIA_BINDIR not set" **Solutions:** 1. Verify `JULIA_BINDIR` is set correctly: `Sys.getenv("JULIA_BINDIR")` 2. Confirm the path exists and contains the Julia executable: ```{r check-julia-path, eval=FALSE} bindir <- Sys.getenv("JULIA_BINDIR") dir.exists(bindir) file.exists(file.path(bindir, "julia.exe")) # Windows file.exists(file.path(bindir, "julia")) # macOS/Linux ``` 3. Set the path explicitly before calling any package functions: ```{r set-julia, eval=FALSE} Sys.setenv(JULIA_BINDIR = "C:/path/to/julia/bin/") ``` ## Circuitscape Not Found **Symptom:** `using Circuitscape` fails with "Package not installed" **Solutions:** 1. Open Julia directly (not from R) and run `Pkg.add("Circuitscape")`. 2. Confirm you are using the correct Julia version: `JuliaConnectoR::juliaEval("string(VERSION)")`. 3. Check that Circuitscape was installed in the default environment, not a project-specific environment: ```julia using Pkg Pkg.activate() # activate default environment Pkg.add("Circuitscape") ``` ## Slow Startup **Symptom:** The first call to `jl.prep()` or `Run_CS.jl()` takes 30–60 seconds. This is normal Julia behavior (JIT compilation on first use). Subsequent calls within the same R session will be much faster because Julia caches compiled code. The startup cost is paid only once per R session. To minimize the impact on optimization runs, call `jl.prep()` once at the beginning of your session (which triggers Julia startup) before beginning optimization. ## Out of Memory **Symptom:** Circuitscape crashes or returns an error about insufficient memory. **Solutions:** 1. Use `precision = TRUE` in `jl.prep()` to switch to single-precision arithmetic. 2. Use `cholmod = FALSE` to switch from the direct CHOLMOD solver to an iterative solver. 3. Aggregate the resistance raster to a coarser resolution. 4. Reduce the number of sample populations if feasible. ## File Permission Errors on Windows **Symptom:** Error messages about inability to write to temporary files. **Solutions:** 1. Set `scratch` in `jl.prep()` to a directory where you have write permissions: ```{r scratch-example, eval=FALSE} jl_inputs <- jl.prep( ..., scratch = "C:/Users/your-name/julia_scratch/" ) ``` 2. Verify that the default `tempdir()` is writable: `dir.exists(tempdir())` ## Connection Drops Mid-Optimization **Symptom:** Julia-related errors appear after the optimization has been running for a while. This can occur if Julia's memory or disk use causes the process to be killed. Solutions: 1. Monitor system resources during the run. 2. Use `precision = TRUE` and/or `cholmod = FALSE` to reduce memory use. 3. Aggregate the raster to a coarser resolution. 4. Split the optimization into smaller chunks (fewer surfaces, smaller GA population). --- # Summary The Julia backend provides Circuitscape-compatible pairwise resistance distances and cumulative current maps from within R. Once Julia and Circuitscape.jl are installed and `JULIA_BINDIR` is set, the interface is nearly identical to the `gdistance` workflow: ``` jl.prep() -> jl_inputs Run_CS.jl() -> pairwise distances or current map SS_optim() -> pass jl.inputs instead of gdist.inputs MS_optim() -> pass jl.inputs instead of gdist.inputs all_comb() -> pass jl.inputs instead of gdist.inputs ``` For iterative optimization on large landscapes or large sample sets, consider using `gdistance::commuteDistance()` for the optimization step and running Circuitscape once with the optimal parameters for final output. # Quick reference: the Julia workflow in one block ```{r julia-quick-reference, eval=FALSE} library(ResistanceGA2) library(terra) # 1. Point ResistanceGA2 at the Julia bin/ directory for this project. JULIA_HOME <- Sys.getenv("JULIA_BINDIR") stopifnot(nzchar(JULIA_HOME), dir.exists(JULIA_HOME)) # 2. Prepare the sample points and response vector. pts <- terra::vect(samples[, 2:3], type = "points") pairwise_genetic <- lower(as.matrix(dist(samples[, 2:3]))) # 3. Build Circuitscape inputs. Use run_test = TRUE the first time on a machine. jl_inputs <- jl.prep( n.Pops = nrow(samples), response = pairwise_genetic, CS_Point.File = pts, JULIA_HOME = JULIA_HOME, run_test = TRUE, silent = TRUE ) # 4. Calculate pairwise Circuitscape distances for one surface. surface <- terra::subset(terra::unwrap(resistance_surfaces), "continuous") cs_vector <- Run_CS.jl( jl.inputs = jl_inputs, r = surface, JULIA_HOME = JULIA_HOME ) # 5. Use jl.inputs in optimization when Circuitscape output is required. surfaces <- resistance_surfaces if (inherits(surfaces, "PackedSpatRaster")) { surfaces <- terra::unwrap(surfaces) } ga_inputs <- GA.prep( raster = surfaces, Results.dir = file.path(tempdir(), "rga2-julia-results") ) ss_out <- SS_optim( GA.inputs = ga_inputs, jl.inputs = jl_inputs ) ``` **How to read the output:** `jl.prep()` returns a configuration list that stores the sample locations, MLPE data frame, solver settings, and Julia path used by the Circuitscape engine. `Run_CS.jl()` returns the pairwise resistance distances that can be modeled like any other resistance-distance vector. `SS_optim()` and `MS_optim()` use the same optimization interface as the `gdistance` workflow, but each candidate surface is evaluated by Circuitscape through Julia. # Summary of key functions | Function | Purpose | |---|---| | `jl.prep()` | Prepare sample points, response data, solver settings, and Julia configuration for Circuitscape-based optimization | | `Run_CS.jl()` | Run the package's optimization-oriented Circuitscape wrapper and return pairwise distances, a matrix, or a current map | | `Run_CS.ini()` | Run Circuitscape with direct `.ini`-style options for advanced scenarios and debugging | | `GA.prep()` | Prepare the raster stack, transformation bounds, and GA control settings used by optimization functions | | `SS_optim()` | Optimize one resistance surface at a time using `jl.inputs` or `gdist.inputs` | | `MS_optim()` | Optimize a composite resistance surface from multiple layers using `jl.inputs` or `gdist.inputs` | # See also - `vignette("GettingStarted", package = "ResistanceGA2")`, the core package workflow and bundled data. - `vignette("ResistanceGA", package = "ResistanceGA2")`, full single-surface, multisurface, all-combinations, and bootstrap optimization examples. - `vignette("Circuitscape_INI", package = "ResistanceGA2")`, direct `.ini`-style Circuitscape control from R. - `vignette("Surface_Transformations", package = "ResistanceGA2")`, transformation families and how the GA searches them. --- # References McRae, B. H. 2006. Isolation by resistance. *Evolution* 60:1551-1561. McRae, B. H., B. G. Dickson, T. H. Keitt, and V. B. Shah. 2008. Using circuit theory to model connectivity in ecology, evolution, and conservation. *Ecology* 89:2712–2724. Peterman, W. E. 2018. ResistanceGA: An R package for the optimization of resistance surfaces using genetic algorithms. *Methods in Ecology and Evolution* 9:1638-1647.