---
title: "Using `terra` with `geotargets`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Using `terra` with `geotargets`}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r}
#| include: false
# With the root.dir option below,
# this vignette runs the R code in a temporary directory
# so new files are written to temporary storage
# and not the user's file space.
knitr::opts_knit$set(root.dir = fs::dir_create(tempfile()))
knitr::opts_chunk$set(
  collapse = TRUE,
  eval = TRUE,
  comment = "#>"
)
```

```{r}
#| label: setup
library(targets)
library(geotargets)
```

The `geotargets` package extends `targets` to work with geospatial data formats, such as rasters and vectors (e.g., shape files).
In particular, `geotargets` aims to support use of the `terra` package, which tend to cause problems if used in targets created with `tar_target()` .
If you are new to `targets`, you should start by looking at the [targets manual](https://books.ropensci.org/targets/) to get a handle on the basics.

The design of `geotargets` is to specify target factories like so: `tar_<pkg>_<type>`.

In this vignette we will demonstrate the use of the `terra` R package, and we will demonstrate how to build raster (`rast`), vector (`vect`), raster collection (`sprc`), and raster dataset (`sds`) targets with:

-   `tar_terra_rast()`
-   `tar_terra_vect()`
-   `tar_terra_sprc()`
-   `tar_terra_sds()`

# How to run targets examples from vignettes

The example code in this vignette is designed for you to be able to just copy and paste into the R console. However, this is not a typical way to run a targets workflow. 

The examples make use of [`targets::tar_script()`](https://docs.ropensci.org/targets/reference/tar_script.html), which creates or overwrites a `_targets.R` file (See for example, the [`_targets.R` file in the demo-geotargets repo](https://github.com/njtierney/demo-geotargets/blob/main/_targets.R)). In these examples, everything inside of `tar_script({})` is what would go inside a `_targets.R` file defining a workflow. When running the `tar_script` code, it will ask you each time if you want to overwrite the `_targets.R` file. This means if you are exploring these examples and copying the entire examples, it is worthwhile doing this in a separate directory/project/repository to avoid overwriting your own `_targets.R` file.

So, when building your own targets workflow it is **not recommended** to use `tar_script()`, but instead to create `_targets.R` and edit `_targets.R` directly.

## `tar_terra_rast()`: targets with `terra` rasters

```{r}
#| label: tar_script_rast
targets::tar_script({
  library(targets)
  library(geotargets)
  tar_option_set(packages = "terra")
  geotargets_option_set(gdal_raster_driver = "COG")
  list(
    tar_target(
      tif_file,
      system.file("ex/elev.tif", package = "terra"),
      format = "file"
    ),
    tar_terra_rast(
      r,
      {
        rast <- rast(tif_file)
        units(rast) <- "m"
        rast
      }
    ),
    tar_terra_rast(
      r_agg,
      aggregate(r, 2)
    )
  )
})
```

Above is a basic example showing the use of `tar_terra_rast()` in a targets pipeline. The command for `tar_terra_rast()` can be any function that returns a `SpatRaster` object.

In this example, we’ve set the output to a cloud optimized geotiff ("COG"), but any GDAL driver that works with `terra::writeRaster()` should also work here. By default, we use "GTiff". You can also set this option on a target-by-target basis with the `filetype` argument to `tar_terra_rast()`.

Running the pipeline:

```{r}
#| label: make-rast
#| echo: true

tar_make()
tar_read(r)
tar_read(r_agg)
```

### Raster metadata

You may have noticed the units for the `r` target above have gone missing.
This is due to limitations of `terra` and `targets`---`terra` saves some metadata in "sidecar" aux.json files and `targets` enforces a strict one file per target rule.

You can get around this by setting `preserve_metadata = "zip"` in `tar_terra_rast()` to save the output files, including the metadata, as a minimally compressed zip archive. 

You can also set this for all raster targets with `geotargets_option_set(terra_preserve_metadata = "zip")`.

Note: there are likely performance costs associated with this option.\
As an alternative, you can encode information in the layer names by setting `names(r) <-` which are retained even with the default `preserve_metadata = "drop"`.

```{r}
#| label: tar_script_rast_metadata
targets::tar_script({
  # contents of _targets.R:
  library(targets)
  library(geotargets)
  tar_option_set(packages = "terra")
  geotargets_option_set(gdal_raster_driver = "COG")
  list(
    tar_target(
      tif_file,
      system.file("ex/elev.tif", package = "terra"),
      format = "file"
    ),
    tar_terra_rast(
      r,
      {
        rast <- rast(tif_file)
        units(rast) <- "m"
        rast
      },
      preserve_metadata = "zip"
    )
  )
})
```

```{r}
#| label: make_rast_metadata
#| echo: true

tar_make()
terra::units(tar_read(r))
```

## `tar_terra_vect()`: targets with `terra` vectors

For `terra` `SpatVector` objects, use `tar_terra_vect()` in the pipeline.
You can set vector specific options with `geotargets_option_set()` or with the `filetype` and `gdal` arguments to individual `tar_terra_vect()` calls.

```{r}
#| label: tar_script_vect

targets::tar_script({
  # contents of _targets.R:
  library(targets)
  library(geotargets)
  geotargets_option_set(gdal_vector_driver = "GeoJSON")
  list(
    tar_target(
      vect_file,
      system.file("ex", "lux.shp", package = "terra"),
      format = "file"
    ),
    tar_terra_vect(
      v,
      terra::vect(vect_file)
    ),
    tar_terra_vect(
      v_proj,
      terra::project(v, "EPSG:2196")
    )
  )
})
```

```{r}
#| label: make_vect
#| echo: true

tar_make()
tar_read(v)
tar_read(v_proj)
```

## `tar_terra_sprc()`: targets with `terra` raster collections

Targets that produce a `SpatRasterCollection` can be created with `tar_terra_sprc()`.
The various rasters in the collection are saved as subdatasets to adhere to `targets` one file per target rule.

```{r}
#| label: tar_script_sprc

targets::tar_script({
  # contents of _targets.R:
  library(targets)
  library(geotargets)
  elev_scale <- function(raster, z = 1, projection = "EPSG:4326") {
    terra::project(
      raster * z,
      projection
    )
  }
  tar_option_set(packages = "terra")
  geotargets_option_set(gdal_raster_driver = "GTiff")
  list(
    tar_target(
      elev_file,
      system.file("ex", "elev.tif", package = "terra"),
      format = "file"
    ),
    tar_target(
      r,
      rast(elev_file)
    ),
    tar_terra_sprc(
      raster_elevs,
      # two rasters, one unaltered, one scaled by factor of 2 and
      # reprojected to interrupted good homolosine
      terra::sprc(list(
        elev_scale(r, 1),
        elev_scale(r, 2, "+proj=igh")
      ))
    )
  )
})
```

```{r}
#| label: make_sprc
#| echo: true

tar_make()
tar_read(raster_elevs)
```

## `tar_terra_sds()`: targets with `terra` raster datasets

A `terra` `SpatRasterDataset` is very similar to a `SpatRasterCollection` except that all sub-datasets must have the same projection and extent

```{r}
#| label: tar_script_sds

targets::tar_script({
  # contents of _targets.R:
  library(targets)
  library(geotargets)
  tar_option_set(packages = "terra")
  list(
    tar_target(
      logo_file,
      system.file("ex/logo.tif", package = "terra"),
      format = "file"
    ),
    tar_terra_sds(
      raster_dataset,
      {
        x <- sds(rast(logo_file), rast(logo_file) / 2)
        names(x) <- c("first", "second")
        x
      }
    )
  )
})
```

```{r}
#| label: make_sds
#| echo: true

tar_make()
tar_read(raster_dataset)
```