This function produces detection probability kernels for incorporation into the acoustic-container* (AC*) algorithms. Within acoustic containers, the incorporation of detection probability kernels reduces uncertainty and increases precision in simulated patterns of space use by up-weighting areas nearer to receivers when an individual is detected and down-weighing areas nearer to receivers when an individual is not detected (see Details).

To implement the function, a SpatialPointsDataFrame that defines receiver IDs, locations and deployment dates must be supplied (via xy). A record of servicing events for receivers can also be supplied (via services). Detection probability kernels are calculated around each receiver, using a user-defined function based on Euclidean distances (calc_detection_pr) across a raster (bathy). Kernels can be restricted by barriers to movement as defined by NAs in bathy and the boundaries of the area. These kernels are used to weight possible locations around a receiver when an individual is detected.

For each unique array design (i.e. set of active receivers, given receiver deployment dates and servicing events, if applicable), a detection probability surface across the whole area is also created, which is used to weight possible locations of the individual in the time steps between detections (up-weighting locations away from receivers). By default, these calculations account for any areas of overlap in the detection probability kernels of multiple receivers. This step is computationally demanding, but it can be suppressed or sped-up via the overlaps argument. Outputs are returned in a named list that is designed to be incorporated into the AC* algorithm(s).

acs_setup_detection_kernels(
  xy,
  services = NULL,
  containers,
  overlaps = NULL,
  calc_detection_pr,
  bathy,
  verbose = TRUE
)

Arguments

xy

A SpatialPointsDataFrame that defines receiver IDs, locations and deployment dates. The data slot must include a dataframe with the following columns: an unique, integer identifier for each receiver (`receiver_id') and receiver deployment Dates (`receiver_start_date' and `receiver_end_date'). For receiver locations, the coordinate reference system should be the Universal Transverse Mercator system with distances in metres (as for bathy, below).

services

(optional) A dataframe that defines receiver IDs and servicing Dates (times during the deployment period of a receiver when it was not active due to servicing). If provided, this must contain the following columns: an integer identifier for serviced receivers (named ‘receiver_id’) and two columns that define the time of the service(s) (‘service_start_date’ and ‘service_end_date’) (see make_matrix_receivers).

containers

The list of detection containers, with one element for each number from 1:max(xy$receiver_id), from acs_setup_containers.

overlaps

(optional) A named list, from get_detection_containers_overlap, that defines, for each receiver, for each day over its deployment period, whether or not its detection container overlapped with those of other receivers. If provided, this speeds up detection probability calculations in overlapping regions by focusing on only the subset of receivers with overlapping detection probability kernels. If there are no overlapping receivers, FALSE can be supplied instead to suppress these calculations.

calc_detection_pr

A function that takes in a vector of distances and returns a vector of detection probabilities (around a receiver). Detection probability should decline to 0 after the detection_range distance from a receiver (see acs_setup_containers).

bathy

A raster of the bathymetry across an area (see ac). Receiver locations and detection probability kernels are represented across this raster. As for xy, the coordinate reference system should be the Universal Transverse Mercator system with distances in metres. Resolution needs to be sufficiently high such that detection probability can be represented effectively, given calc_detection_pr, but sufficiently low for convenient run times. If bathy contains NAs, it is also taken as a mask that is applied to detection probability kernels to remove `impossible` areas (e.g., on land).

verbose

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

Value

The function returns a named list with five elements:

  1. receiver_specific_kernels. A list, with one element for all integers from 1 to the maximum receiver number. Any elements that do not correspond to receivers contain a NULL element. List elements that correspond to receivers contain a raster of the detection probability kernel around the relevant receiver. Cells values define the detection probability around a receiver, given calc_detection_pr. In the AC* algorithm(s), these kernels are used to up-weight location probabilities near to a receiver when it is detected (following modification to account for overlapping areas, if necessary).

  2. receiver_specific_inv_kernels. A list, as for receiver_specific_kernels, but in which elements contain the inverse detection probability kernels (i.e., 1 - detection probability). In the AC* algorithm(s), these is used to down-weight-weight location probabilities in the overlapping regions between a receiver that recorded detections and others that did not at the same time.

  3. array_design_intervals. A dataframe that defines the number and deployment times of each unique array design, resulting from receiver deployment, servicing and removal. In the times between detections, this is used to select the appropriate `background' detection probability surface (see below). This contains the following columns:

    • array_id An integer vector that defines each unique array design.

    • array_start_date A Date that defines the start date of each array design.

    • array_end_date A Date that defines the end date of each array design.

    • array_interval An Interval-class vector that defines the deployment period of each array design.

  4. bkg_surface_by_design. A list, with one element for each array design, that defines the detection probability surface across all receivers deployed in that phase of the study. In areas that are covered by the detection probability kernel of a single receiver, the detection probability depends only on distance to that receiver (via calc_detection_pr). In areas covered by multiple, overlapping kernels, detection probability represents the combined detection probability across all overlapping kernels (see Details).

  5. bkg_inv_surface_by_design. A list, as above for bkg_surface_by_design, but which contains the inverse detection probability surface (i.e., 1 - bkg_surface_by_design). In the AC* algorithm(s), this is used to up-weight areas away from receivers (or, equivalently, down-weight areas near to receivers) in the time steps between detections.

Details

A detection probability kernel is a bivariate probability density function that describes detection probability around a receiver. Typically, this takes the shape of a dome whereby detection probability declines uniformly around a receiver with increasing distance. Accordingly, this function assumes that detection probability kernels only depend on distance (via calc_detection_pr) and are constant in space and time. Spatially variable detection probability kernels can be incorporated just as easily into the AC* algorithm(s) but need to be created manually. For example, in areas of complex coastline, narrow peninsulas that punctuate detection containers may effectively block transmissions from the outer regions of detection containers from being detected at receivers, in which case a model that incorporates the `line of sight' between receivers and the surrounding regions may be appropriate. However, temporally variable detection probability kernels are not currently supported by the AC* algorithm(s).

The purpose of detection probability kernels within the AC* algorithm(s) is to reduce the uncertainty of the possible positions of an individual within the acoustic containers, both when an individual is detected and when it is not. When an individual is detected at a receiver, a central assumption of the AC* algorithm(s) is that the individual is within a finite radius of that receiver in an area defined as the ‘detection container’. Under the simplest implementation of the algorithm, this represents a threshold detection probability model in which the probability of detection is certain within the container and zero outside. Under this model, the individual is equally likely to have been in any location within the container and all possible locations of the individual are weighted equally. This approach is suitable for the most conservative analyses, since even unlikely positions of the individual receive equal weighting. However, detection probability typically declines with distance around a receiver and the incorporation of this information in the form of kernels around the receiver at which is detected (and any receivers with overlapping kernels) improve precision by increasing the weighting for some areas over others. The way in which this increase in precision is realised over space depends on whether or not detection probability kernels and the timing of detections at multiple receivers overlap.

In the simplest scenario, an individual is detected at a receiver whose container does not overlap with any other receiver and the kernel simply increases the weight of locations nearest to the receiver (according to a user-specified detection probability function). For some array designs, an alternative possibility is that an individual is detected at a receiver whose container overlaps with other receiver(s). In this case, detection or lack of detection at the same moment at the receivers with overlapping containers provides further information on the location of the individual. One the one hand, if the individual is not detected at the other receiver(s), then the probability that the individual is in the overlapping region(s) is reduced in line with the overlap in detection probability, which decreases the weight of potential locations in these areas. On the other hand, if the individual is detected at effectively the same time at multiple receiver(s), then the individual is more likely to be within the overlapping parts of their containers, and the weight of possible locations here is correspondingly elevated. The definition of ‘effectively’ is context specific but depends on the accuracy with which the clocks of different receivers are synchronised. (For example, ± 5 s might be reasonable.) In these situations, the detection container essentially just acts as a computational device by restricting calculations to the container(s) and ‘cutting’ the probability of detection to zero beyond this area. This process follows the standard rules of probability.

When an individual is not detected, the detection container grows into a set of ‘acoustic containers’ that contain the set of possible locations for the individual. As they grow, they may encompass other detection containers before they shrink towards the receiver at which the individual is next detected. During this time, the AC* algorithm(s) identify the possible locations of the individual within these areas. Under the most conservative approach, at each time step all positions are treated as equally likely (although normalisation within the algorithm(s) effectively down-weights time steps in which the location of the individual is more uncertain). This includes any positions within the detection containers of other receivers since, under realistic conditions, there is usually a non-zero probability that an individual can be near a receiver and yet remain undetected. However, this is typically unlikely and when the goal of the analysis is to create more precise estimates of space use, the incorporation of detection probability kernel(s) around receivers effectively reduces the probability that the individual is within their detection containers during this time. Again, to incorporate detection probability kernels in this way, it is necessary to account for overlapping detection ranges, where the probability of detection is higher and, therefore, the probability of a possible location in such an area is lower given the absence of a detection. As above, this process follows the laws of probability.

In summary, in the AC* algorithm(s), detection and acoustic containers describe the spatial extent of our uncertainty when an individual is detected and in the time between detections respectively. The purpose of this function is to pre-process and package the information provided by detection probability kernels in such a way as to facilitate its incorporation into the AC* algorithm(s). This improves the precision of simulated patterns of space use by down- or up-weighting areas according to a model of detection probability. This provides a reasonable overall assessment of the places in which an individual could have spend more or less time over a period of study.

However, it is worth noting that, within acoustic containers, unrealistic areas may be highlighted in which an individual could not have been located because of movement constraints which are not captured by container-level expansion and contraction. For example, there may be parts of a container that are highly unlikely given a detection at a nearby receiver because they are too far away from the receiver at which the individual was subsequently detected. In the AC*PF algorithm(s), the incorporation of a movement model further reduces uncertainty by accounting for the constraints imposed by an individual’s current position on its next position.

See also

This is one of a number of functions used to set up the AC and ACDC algorithms implemented by ac and acdc: acs_setup_mobility, acs_setup_containers and acs_setup_detection_kernels. This function is supported by make_matrix_receivers, which defines receiver activity statuses; acs_setup_containers, which defines acoustic containers; and get_detection_containers_overlap, which defines detection container overlaps

Author

Edward Lavender

Examples

#### Set up data for examples

## Define receiver IDs, locations and deployment dates
# Focus on a subset of receivers for example speed
moorings <- dat_moorings[1:5, ]
# Define receiver locations as a SpatialPoints object with a UTM CRS
proj_wgs84 <- sp::CRS(SRS_string = "EPSG:4326")
proj_utm <- sp::CRS(SRS_string = "EPSG:32629")
xy <- sp::SpatialPoints(
  moorings[, c("receiver_long", "receiver_lat")],
  proj_wgs84
)
xy <- sp::spTransform(xy, proj_utm)
# Link receiver IDs, locations and deployment dates to form a SpatialPointsDataFrame
# ... Note required column names and class types.
xy <- sp::SpatialPointsDataFrame(xy, moorings[, c(
  "receiver_id",
  "receiver_start_date",
  "receiver_end_date"
)])

## Define bathymetric map of area for which AC* algorithm(s) will be implemented
# ... The resolution must be sufficiently high
# ... such that there are areas with non zero detection probability.
# ... However, function speed will fall with large, high resolution rasters.
# ... Here, we set a low resolution for example speed.
surface <- raster::raster(raster::extent(dat_gebco), res = c(50, 50))
surface <- raster::resample(dat_gebco, surface)

## Define detection probability function
# This should depend on distance alone
# Detection probability should decline to 0 after detection_range
# ... (defined in flapper::acs_setup_containers()).
# ... Here, we assume detection_range = 425 m.
calc_dpr <-
  function(x) {
    ifelse(x <= 425, stats::plogis(2.5 + -0.02 * x), 0)
  }
plot(0:1000, calc_dpr(0:1000), type = "l")


## Get detection containers and, if applicable, information on their overlap(s)
# We'll use the example containers provided in dat_containers
# We'll get their overlaps via flapper::get_detection_containers_overlap
overlaps <-
  get_detection_containers_overlap(
    containers = get_detection_containers(xy = xy, byid = TRUE)
  )
#> Warning: GEOS support is provided by the sf and terra packages among others


#### Example (1): Implement function using default options
kernels <- acs_setup_detection_kernels(
  xy = xy,
  containers = dat_containers,
  overlaps = overlaps,
  calc_detection_pr = calc_dpr,
  bathy = surface
)
#> flapper::acs_setup_detection_kernels() called (@ 2023-08-29 15:35:21)... 
#> ... Setting up function... 
#> ... Getting receiver-specific kernels (for detection)... 
#> 
#> ... ... For receiver 3 ... 
#> ... ... ... Isolating detection container ... 
#> ... ... ... Calculating distances from the receiver ... 
#> ... ... ... Calculating detection probability ... 
#> ... ... ... Processing kernel ... 
#> 
#> ... ... For receiver 4 ... 
#> ... ... ... Isolating detection container ... 
#> ... ... ... Calculating distances from the receiver ... 
#> ... ... ... Calculating detection probability ... 
#> ... ... ... Processing kernel ... 
#> 
#> ... ... For receiver 7 ... 
#> ... ... ... Isolating detection container ... 
#> ... ... ... Calculating distances from the receiver ... 
#> ... ... ... Calculating detection probability ... 
#> ... ... ... Processing kernel ... 
#> 
#> ... ... For receiver 9 ... 
#> ... ... ... Isolating detection container ... 
#> ... ... ... Calculating distances from the receiver ... 
#> ... ... ... Calculating detection probability ... 
#> ... ... ... Processing kernel ... 
#> 
#> ... ... For receiver 11 ... 
#> ... ... ... Isolating detection container ... 
#> ... ... ... Calculating distances from the receiver ... 
#> ... ... ... Calculating detection probability ... 
#> ... ... ... Processing kernel ... 
#> ... Getting receiver-specific inverse kernels... 
#> ... Getting area-wide kernels (for non-detection)... 
#> ... ... Get unique array designs... 
#> ... ... Get area wide kernels for each array design... 
#> 
#> ... ... ... For design 1/5... 
#> ... ... ... ... Extract detection probability kernels for active receivers... 
#> ... ... ... ... Combining detection kernels to calculate the background detection probability surfaces (this is a slow step)... 
#> 
#> ... ... ... For design 2/5... 
#> ... ... ... ... Extract detection probability kernels for active receivers... 
#> ... ... ... ... Combining detection kernels to calculate the background detection probability surfaces (this is a slow step)... 
#> 
#> ... ... ... For design 3/5... 
#> ... ... ... ... Extract detection probability kernels for active receivers... 
#> ... ... ... ... Combining detection kernels to calculate the background detection probability surfaces (this is a slow step)... 
#> 
#> ... ... ... For design 4/5... 
#> ... ... ... ... Extract detection probability kernels for active receivers... 
#> ... ... ... ... Combining detection kernels to calculate the background detection probability surfaces (this is a slow step)... 
#> 
#> ... ... ... For design 5/5... 
#> ... ... ... ... Extract detection probability kernels for active receivers... 
#> ... ... ... ... Combining detection kernels to calculate the background detection probability surfaces (this is a slow step)... 
#> ... Process detection probability kernels ... 
#> ... flapper::acs_setup_detection_kernels() call completed (@ 2023-08-29 15:35:22) after ~0.02 minutes. 

# Examine list elements
summary(kernels)
#>                               Length Class      Mode
#> receiver_specific_kernels     11     -none-     list
#> receiver_specific_inv_kernels 11     -none-     list
#> array_design_intervals         4     data.frame list
#> bkg_surface_by_design          5     -none-     list
#> bkg_inv_surface_by_design      5     -none-     list

# Examine example receiver-specific kernels
pp <- graphics::par(mfrow = c(1, 2))
raster::plot(kernels$receiver_specific_kernels[[3]])
points(xy[xy$receiver_id == 3, ], cex = 2)
raster::plot(kernels$receiver_specific_kernels[[4]])
points(xy[xy$receiver_id == 4, ], cex = 2)

graphics::par(pp)

# Examine example receiver-specific inverse kernels
pp <- graphics::par(mfrow = c(1, 2))
raster::plot(kernels$receiver_specific_inv_kernels[[3]])
points(xy[xy$receiver_id == 3, ], cex = 2)
raster::plot(kernels$receiver_specific_inv_kernels[[4]])
points(xy[xy$receiver_id == 4, ], cex = 2)

graphics::par(pp)

# Examine background detection Pr surfaces
# (for each unique combination of receivers that were deployed)
pp <- graphics::par(mfrow = c(2, 3), mar = c(0, 0, 0, 0))
lapply(kernels$bkg_surface_by_design, function(bkg) {
  raster::plot(bkg, axes = FALSE)
  graphics::box()
})
#> [[1]]
#> NULL
#> 
#> [[2]]
#> NULL
#> 
#> [[3]]
#> NULL
#> 
#> [[4]]
#> NULL
#> 
#> [[5]]
#> NULL
#> 
graphics::par(pp)


# Examine background inverse detection Pr surfaces
pp <- graphics::par(mfrow = c(2, 3), mar = c(0, 0, 0, 0))
lapply(kernels$bkg_inv_surface_by_design, function(bkg) {
  raster::plot(bkg, axes = FALSE)
  graphics::box()
})
#> [[1]]
#> NULL
#> 
#> [[2]]
#> NULL
#> 
#> [[3]]
#> NULL
#> 
#> [[4]]
#> NULL
#> 
#> [[5]]
#> NULL
#> 
graphics::par(pp)