---
title: "Anisotropic shortest paths across the Strait of Gibraltar"
author: "Javier Fernández-López and Klaus Schliep"
date: "`r format(Sys.Date(), '%B %d, %Y')`"
bibliography: rWind.bib
nocite: |
  @terra
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Anisotropic shortest paths across the Strait of Gibraltar}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 6
)
suppressPackageStartupMessages(library(rWind))
if (utils::packageVersion("rWind") < "1.2.0") {
  stop(
    "This vignette requires rWind >= 1.2.0. Install the current package ",
    "source before knitting it."
  )
}
suppressPackageStartupMessages(library(terra))
suppressPackageStartupMessages(library(gdistance))
```

## Overview

This vignette shows the core rWind workflow: obtain wind data, represent them
as modern spatial rasters, translate wind speed and direction into anisotropic
movement conductance, and calculate directional least-cost paths.

The example crosses the Strait of Gibraltar. Because wind-assisted movement is
direction dependent, the least-cost path from Spain to Morocco does not
necessarily match the path in the opposite direction.

## Obtain wind data

`wind.dl()` automatically selects the appropriate data source. Current dates
are requested from PacIOOS, whereas older dates are retrieved from the
NOAA/NCEI GFS archive. GFS data are available at three-hour UTC intervals.

The download call used for this example is:

```{r download, eval=FALSE}
w <- wind.dl(
  2015, 2, 12, 12,
  lon1 = -7, lon2 = -4,
  lat1 = 34.5, lat2 = 37.5
)
```

To make the vignette reproducible without a network connection, it uses the
result saved with the package.

```{r cached-data}
w <- readRDS("w.rds")
head(w)
```

## Create a `SpatRaster`

`wind2raster()` converts the tabular result into a two-layer
`terra::SpatRaster` [@terra]. The layers are named `direction` and `speed`, and
the coordinate reference system is WGS 84 (EPSG:4326).

```{r create-raster}
wind_layer <- wind2raster(w)
wind_layer
```

Individual layers use standard `terra` syntax:

```{r inspect-speed}
wind_layer[["speed"]]
```

## Build directional conductance

For passive movement, `flow.dispersion()` applies a restricted version of the
formulation of Felicísimo et al. [-@felicisimo2008]. Deviations of 90 degrees
or more from the flow are treated as barriers. The resulting `TransitionLayer`
stores directional conductance and can be used by `gdistance` [@gdistance].
Internally, rWind converts only the direction layer to the legacy raster
representation required by `gdistance`; the public spatial representation
remains a `SpatRaster`.

```{r conductance}
conductance <- flow.dispersion(wind_layer, type = "passive")
conductance
```

Every transition cost is the mean of the local costs at the origin and
destination cells. Diagonal transitions are multiplied by `sqrt(2)`. This
corrects diagonal length on an abstract square grid, but not the changing
physical distances of longitude/latitude cells.

### Active movement

The optional active model is deliberately general rather than mechanistic. It
uses the signed component of flow parallel to movement. Let
`z = speed * cos(angle) / speed.scale`: supportive flow (`z >= 0`) has cost
`1 / (1 + z)`, while opposing flow has cost `1 - z`. Perpendicular flow is
neutral and movement against the flow remains possible.

```{r active-conductance}
active_conductance <- flow.dispersion(
  wind_layer,
  type = "active",
  speed.scale = median(w$speed[w$speed > 0], na.rm = TRUE)
)
active_conductance
```

If `speed.scale` is omitted, rWind uses the median positive speed of the raster.
Supply one fixed value when comparing dates or regions. Active costs are
relative connectivity indices: they are not estimates of travel time, energy,
or an organism's intrinsic movement speed.

## Calculate paths in both directions

```{r paths}
spain <- c(-5.5, 37)
morocco <- c(-5.5, 35)

spain_to_morocco <- shortestPath(
  conductance, spain, morocco,
  output = "SpatialLines"
)
morocco_to_spain <- shortestPath(
  conductance, morocco, spain,
  output = "SpatialLines"
)
```

The following map uses `terra` for the raster and path representation. Wind
arrows are drawn from the downloaded U and V components; their lengths are
scaled for display.

```{r map}
plot(
  wind_layer[["speed"]],
  col = hcl.colors(20, "YlOrRd", rev = TRUE),
  main = "Wind-assisted paths across the Strait of Gibraltar",
  xlab = "Longitude", ylab = "Latitude"
)

lines(vect(spain_to_morocco), col = "#C62828", lwd = 3, lty = 2)
lines(vect(morocco_to_spain), col = "#1565C0", lwd = 3, lty = 2)
points(spain[1], spain[2], pch = 19, cex = 1.3, col = "#C62828")
points(morocco[1], morocco[2], pch = 19, cex = 1.3, col = "#1565C0")

arrow_scale <- 0.12 / max(w$speed, na.rm = TRUE)
arrows(
  w$lon, w$lat,
  w$lon + w$ugrd10m * arrow_scale,
  w$lat + w$vgrd10m * arrow_scale,
  length = 0.035, col = "grey20"
)

text(spain[1], spain[2] + 0.18, "Spain", col = "#C62828", font = 2)
text(morocco[1], morocco[2] - 0.18, "Morocco", col = "#1565C0", font = 2)
legend(
  "topleft",
  legend = c("Spain to Morocco", "Morocco to Spain"),
  col = c("#C62828", "#1565C0"),
  lwd = 3, lty = 2, cex = 0.8, bg = "white"
)
```

The two paths differ because the conductance matrix is asymmetric: travelling
with the wind has a different cost from travelling against it. For larger
areas or long time series, both raster size and the number of possible cell
transitions increase rapidly, so start with the smallest spatial extent and
resolution needed for the biological question.

## References
