This function is designed to simulate different kinds of array designs for monitoring stations. The function has been particularly inspired by the need to simulate passive acoustic telemetry array designs, which comprise networks of acoustic hydrophones that listen for acoustic transmissions from tagged marine animals. To implement the function, it is necessary to define the boundaries of the area (boundaries). Barriers to movement, such as coastline, within this area can be simulated or included from real datasets. The area is populated with a specified number of receivers (n_receivers) that are simulated under different array designs (namely, regular, random, stratified, non-aligned, hexagonal and clustered arrangements) or incorporated from real data. The function returns a list of spatial objects that define the array and, if requested, a plot of the area.

sim_array(
  boundaries = raster::extent(-10, 10, -10, 10),
  coastline = NULL,
  land_inside_coastline = TRUE,
  n_receivers = 10L,
  arrangement = "random",
  seed = NULL,
  plot = TRUE,
  xlim = NULL,
  ylim = NULL,
  add_sea = NULL,
  add_land = NULL,
  add_receivers = list(),
  verbose = TRUE,
  ...
)

Arguments

boundaries

An extent object that defines the boundaries of the (simulated) study area.

coastline

(optional) This argument is used to incorporate the presence of barriers, such as coastline, in the area. There are three options. If coastline = NULL, no barriers are incorporated. If coastline = "simple_random", then a triangular island is simulated in the study area. Alternatively, a spatial object (such as a SpatialPolygonsDataFrame) or a raster that defines the coastline in an area can be incorporated into the array design by passing this coastline. If a raster is used, cells with NA are excluded from sampling.

land_inside_coastline

If coastline is a Spatial okject, land_inside_coastline is a logical variable that defines whether or not the land is `inside' the polygon(s) defined by coastline (land_inside_coastline = TRUE) or the sea is `inside' the polygon(s) (land_inside_coastline = FALSE).

n_receivers

An integer that defines the number of receivers in the array. This is ignored if receiver locations are specified via arrangement.

arrangement, ...

A character string or a SpatialPoints object that defines the arrangement of receivers. If a character is supplied, sampling is implemented via spsample unless coastline is a raster in which case sampling is implemented via sampleRegular, sampleRandom or sampleStratified, depending on arrangement. Supported character string options for simulated arrays are "regular", "random", "stratified" (for all supported function inputs) and "nonaligned", "hexagonal" and "clustered" (only for spsample implementations). Additional arguments can be passed to this function via ... for further control. Otherwise, a SpatialPoints object that defines the coordinates of receivers (in the same coordinate reference system as boundaries and, if applicable, coastline) is assumed to have been provided.

seed

An integer that is used to set the seed to enable reproducible simulations (see set.seed).

plot

A logical variable that defines whether or not plot the array (via pretty_map).

xlim, ylim

(optional) Axis limits for the plot. These can be specified in any way supported by pretty_axis.

add_sea, add_land, add_receivers

(optional) Named lists of arguments, passed to pretty_map, to customise the appearance of the sea, land and/or receivers on the plot. add_* = NULL suppresses the addition of the layer to the plot. To use the default graphical parameters, simply specify add_* = list().

verbose

A logical variable that defines whether or not to print messages to the console to relay function progress.

Value

The function returns a named list of (a) the spatial objects that define the simulated array (`array') and (b) the arguments used to generate this array (`args'). The `array' element is a named list contains the following elements: `boundaries', an Extent-class object that defines the boundaries of the area (as inputted); `area', a SpatialPolygons-class object that defines the boundaries of the area; `land' and `sea', SpatialPolygons-class, SpatialPolygonsDataFrame-class or raster objects that define the land and sea respectively; and `xy', a SpatialPoints-class object that defines receiver locations. If plot = TRUE, the function also returns a plot of the array.

Details

Note that this function does not currently support temporally varying array designs.

For coupled simulation--analysis workflows (such as sim_array, sim_path_sa and sim_detections plus ac, dc, acdc and pf) note that the representation of the coastline as SpatialPolygons-class or SpatialPolygonsDataFrame-class objects by the sim_* functions, rather than a raster grid, may be problematic at the land--sea interface if the Spatial* data used for the simulation do not agree precisely with the raster data used to reconstruct movements: locations that are `allowed' from the perspective of the Spatial* data may not be allowed by the raster data (and vice versa). At the time of writing, this can be resolved in two ways. (A) Check simulated array positions in relation to the grid across which movements are reconstructed. Receiver locations should also be translated onto the raster before simulating detections (see sim_detections). (B) For this function, you can now use a raster to simulate receiver locations (see also acs_setup_containers).

See also

sim_array, sim_path_* and sim_detections provide an integrated workflow for simulating acoustic arrays, movement paths in these areas and detections at receivers arising from movement.

Author

Edward Lavender

Examples

#### Example (1): Simulate an array using default parameters
# ... And force reproducible simulations by defining the seed
array <- sim_array(
  boundaries = raster::extent(-10, 10, -10, 10),
  seed = 1
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 

#### Example (2): Simulate coastline and customise plot
# ... via add_land and add_sea
array <- sim_array(
  boundaries = raster::extent(-10, 10, -10, 10),
  coastline = "simple_random",
  add_land = list(col = "darkgreen"),
  add_sea = list(col = scales::alpha("skyblue", 0.2)),
  seed = 1
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating coastline... 
#> ... ... Simulating coastline... 
#> Warning: less than 4 coordinates in polygon
#> Warning: GEOS support is provided by the sf and terra packages among others
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -4.689827, 1.457067, -5.966361, 8.164156  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> $col
#> [1] "darkgreen"
#> 
#> $x
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -4.689827, 1.457067, -5.966361, 8.164156  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> 
#> $col
#> [1] "#87CEEB33"
#> 
#> $x
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> 
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 

#### Example (3): Add custom coastline
array <- sim_array(
  boundaries = raster::extent(dat_coast),
  coastline = dat_coast,
  add_land = list(col = "darkgreen"),
  add_sea = list(col = scales::alpha("skyblue", 0.2)),
  seed = 1
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> ... Incorporating coastline... 
#> Warning: GEOS support is provided by the sf and terra packages among others
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : 697637.7, 712448.9, 6248627, 6270681  (xmin, xmax, ymin, ymax)
#> crs         : +proj=utm +zone=29 +datum=WGS84 +units=m +no_defs 
#> $col
#> [1] "darkgreen"
#> 
#> $x
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> 
#> $col
#> [1] "#87CEEB33"
#> 
#> $x
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : 697637.7, 712448.9, 6248627, 6270681  (xmin, xmax, ymin, ymax)
#> crs         : +proj=utm +zone=29 +datum=WGS84 +units=m +no_defs 
#> 
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: '+proj=utm +zone=29 +datum=WGS84 +units=m +no_defs'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 

#### Example (4): Change the number of receivers
array <- sim_array(n_receivers = 5)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 

#### Example (5): Change the arrangement of receivers
## Explore different arrangements
array <- sim_array(n_receivers = 25, arrangement = "random")
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25, arrangement = "regular")
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25, arrangement = "clustered", nclusters = 5)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25, arrangement = "stratified")
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25, arrangement = "nonaligned")
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
array <- sim_array(n_receivers = 25, arrangement = "hexagonal")
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> NULL
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> NULL
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
## Force arrangements around coastline
# Simulated island
array <- sim_array(
  n_receivers = 25,
  coastline = "simple_random",
  arrangement = "regular",
  add_land = list()
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> CRS of area is NA.
#> ... Incorporating coastline... 
#> ... ... Simulating coastline... 
#> Warning: less than 4 coordinates in polygon
#> Warning: GEOS support is provided by the sf and terra packages among others
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -3.632555, -2.500754, 0.7677006, 5.374274  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -10, 10, -10, 10  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> $x
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : -3.632555, -2.500754, 0.7677006, 5.374274  (xmin, xmax, ymin, ymax)
#> crs         : NA 
#> 
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: 'NA'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
# Real coastline
array <- sim_array(
  boundaries = raster::extent(dat_coast),
  n_receivers = 25,
  coastline = dat_coast,
  arrangement = "regular",
  add_land = list()
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:13)... 
#> ... Defining area... 
#> ... Incorporating coastline... 
#> Warning: GEOS support is provided by the sf and terra packages among others
#> ... Incorporating receivers... 
#> ... ... Simulating receivers... 
#> ... Plotting array... 
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : 697637.7, 712448.9, 6248627, 6270681  (xmin, xmax, ymin, ymax)
#> crs         : +proj=utm +zone=29 +datum=WGS84 +units=m +no_defs 
#> $x
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> 
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: '+proj=utm +zone=29 +datum=WGS84 +units=m +no_defs'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:13) after ~0 minutes. 
## Incorporate custom arrangements
# Define receiver locations as a SpatialPoints object with a UTM CRS
# ... to match other spatial datasets
proj_wgs84 <- sp::CRS(SRS_string = "EPSG:4326")
proj_utm <- sp::CRS(SRS_string = "EPSG:32629")
xy <- sp::SpatialPoints(
  dat_moorings[, c("receiver_long", "receiver_lat")],
  proj_wgs84
)
xy <- sp::spTransform(xy, proj_utm)
# Make array
array <- sim_array(
  boundaries = raster::extent(dat_coast),
  coastline = dat_coast,
  arrangement = xy,
  add_land = list()
)
#> flapper::sim_array() called (@ 2023-08-29 15:46:14)... 
#> ... Defining area... 
#> ... Incorporating coastline... 
#> Warning: GEOS support is provided by the sf and terra packages among others
#> ... Incorporating receivers... 
#> ... Plotting array... 
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> class       : SpatialPolygons 
#> features    : 1 
#> extent      : 697637.7, 712448.9, 6248627, 6270681  (xmin, xmax, ymin, ymax)
#> crs         : +proj=utm +zone=29 +datum=WGS84 +units=m +no_defs 
#> $x
#> Object of class "SpatialPolygonsDataFrame" (package sp):
#> 
#> Number of SpatialPolygons:  1
#> 
#> Variables measured:
#>   GID_0         NAME_0
#> 1   GBR United Kingdom
#> 
#> 
#> NULL
#> NULL
#> prettyGraphics::pretty_map() CRS taken as: '+proj=utm +zone=29 +datum=WGS84 +units=m +no_defs'.

#> ... Defining outputs... 
#> ... flapper::sim_array() call completed (@ 2023-08-29 15:46:14) after ~0 minutes.