This function implements the arithmetic mean-position algorithm to calculate an individual's centres of activity (COAs) though time from detections at passive acoustic telemetry receivers, as described by Simpfendorfer et al (2002). Under this approach, each COA is calculated as the arithmetic mean of the locations of receivers at which an individual was detected over a specified time interval, weighted by the frequency of detections at each of those receivers. To implement the function, a detection matrix that defines the number of detections of an individual along sequence of time steps at each receiver (e.g., from make_matrix_detections) needs to be supplied, along a matrix of receiver locations in a planar coordinate system. For each time interval, the function calculates the centre of activity and returns a matrix or dataframe with this information.

coa(
  mat,
  xy,
  cl = NULL,
  varlist = NULL,
  na_omit = TRUE,
  as_POSIXct = as.POSIXct,
  output = "matrix"
)

Arguments

mat

A detection matrix, with one row for each time step and one column for each receiver, in which each cell defines the number of detections at each time step/receiver (for a particular individual) (see make_matrix_detections). It is advisable that the rows and columns of this matrix are labelled by time stamp and receiver respectively, especially if there are any rows without detections (see output below).

xy

A matrix that defines receiver locations (x, y). This should contain one row for each receiver (column) in mat (in the same order as in mat) and two columns for the coordinates. Planar coordinates (i.e., in Universal Transverse Mercator projection) are required for the averaging process.

cl, varlist

(optional) Parallelisation options. cl is (a) a cluster object from makeCluster or (b) an integer that defines the number of child processes. varlist is a character vector of variables for export (see cl_export). Exported variables must be located in the global environment. If a cluster is supplied, the connection to the cluster is closed within the function (see cl_stop). For further information, see cl_lapply and flapper-tips-parallel.

na_omit, as_POSIXct

Processing options. na_omit is a logical variable that defines whether or not to omit NAs (i.e., rows in mat for which no detections were made and thus for which COAs cannot be calculated) from returned coordinates. If output = "data.frame" (see below), as_POSIXct is a function to convert time stamps, taken from the row names of mat, to a POSIXct vector. as_POSIXct = NULL suppresses this conversion.

output

A character that defines the output format. Currently supported options are: "matrix", which returns a matrix of the coordinates of COAs; and "data.frame", which returns a dataframe with timestamps (taken from the row names of mat) and COA coordinates.

Value

The function returns a matrix or a dataframe, depending on the output argument, that represents a time series of COAs. If na_omit = TRUE, the time series may have `gaps' over which COAs could not be calculated due to the absence of detections.

Details

Centres of activity (COA) are a widely used metric for the reconstruction of patterns of space use from passive acoustic telemetry detections. Several methods have been developed to calculate COAs, but the mean-position algorithm is the commonest. Under this approach, COAs are estimated as an average of the locations of receivers at which an individual is detected over a specified time interval, weighted by the frequency of detections at each of those receivers. Within flapper, COAs are calculated in three stages by first exploring possible time intervals over which to calculate COAs with coa_setup_delta_t; then summarising detections over those intervals with make_matrix_detections; and finally passing the resultant detection matrix to the coa function to calculate COAs. This implements the arithmetic version of the mean-position algorithm, calculating the arithmetic mean of the receiver locations, weighted by the frequency of detections at each receiver.

To generate estimates of space use, COAs are usually taken as point estimates from which utilisation distributions (typically kernel utilisation distributions, KUDs) are estimated. Thus, in the case of a coupled COA-KUD approach, usually the estimate of space use is a (kernel) utilisation distribution which describes the probability of relocating an individual in any given area at a randomly chosen time. Alternative methods of home range analysis, including those which incorporate time, such as dynamic Brownian bridge movement models, can be used to estimate the utilisation distribution. Generally, the COA approach is most suitable when detections are relatively frequent, and receivers are regularly distributed across an area. Under other conditions, its performance as a method for estimating space use has been subject to relatively limited evaluation but it can be problematic (e.g., in clustered arrays).

References

Simpfendorfer, C. A., M. R. Heupel, and R. E. Hueter. 2002. Estimation of short-term centers of activity from an array of omnidirectional hydrophones and its use in studying animal movements. Canadian Journal of Fisheries and Aquatic Sciences 59:23-32.

See also

coa_setup_delta_t suggests suitable time intervals over which to calculate COAs. make_matrix_detections makes the detection matrices from detection time series data required by this function. For data in the VEMCO Vue export format, the `COA' function in the VTrack package (https://github.com/RossDwyer/VTrack) can also be used to calculate centres of activity.

Author

Edward Lavender

Examples

#### Define data for the calculation of COAs

## (1) Define the period over which to calculate COAs
# ... by focusing on the time over which IDs were at liberty.
dat_ids$tag_start_date <- as.POSIXct(dat_ids$tag_start_date)
dat_ids$tag_end_date <- as.POSIXct("2017-06-02")

## (2) Define the receivers over which to calculate detections
# ... Here we use factors to ensure that the order of receiver coordinates
# ... (see below) and the order or receivers in the detection matrix
# ... matches.
dat_moorings$receiver_id <- factor(dat_moorings$receiver_id)
dat_acoustics$receiver_id <- factor(dat_acoustics$receiver_id,
  levels = levels(dat_moorings$receiver_id)
)

## (3) Define the detection matrix
# ... Here we simply create a detection matrix across all IDs and using
# ... a convenient (but unjustified) delta_t value. In reality, we would need
# ... to consider the time series for which to calculate
# ... COAs and the appropriate delta t value(s) more carefully.
detection_matrix_by_id <- make_matrix_detections(dat_acoustics,
  delta_t = "days",
  start = min(dat_ids$tag_start_date),
  end = max(dat_ids$tag_end_date)
)
#> flapper::make_matrix_detections() called (@ 2023-08-29 15:37:13)... 
#> ... Checking user inputs... 
#> ... Defining time bins given 'delta_t'... 
#> ... Making detection matrix... 
#> ... flapper::make_matrix_detections() call completed (@ 2023-08-29 15:37:13) after ~0 minutes. 

## (4) Define receiver coordinates with UTM projection
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)
xy <- sp::coordinates(xy)

#### Example (1): Implement the COA algorithm for an example individual
coa_mat <- coa(mat = detection_matrix_by_id[[1]], xy = xy)
utils::str(coa_mat)
#>  num [1:255, 1:2] 709191 709276 709276 707542 705754 ...
#>  - attr(*, "dimnames")=List of 2
#>   ..$ : chr [1:255] "2016-03-17 01:00:00" "2016-03-21 01:00:00" "2016-03-22 01:00:00" "2016-03-23 01:00:00" ...
#>   ..$ : chr [1:2] "x" "y"
#>  - attr(*, "na.action")= 'omit' Named num [1:197] 1 2 3 4 5 6 7 8 9 10 ...
#>   ..- attr(*, "names")= chr [1:197] "2016-03-07 01:00:00" "2016-03-08 01:00:00" "2016-03-09 01:00:00" "2016-03-10 01:00:00" ...

#### Example (2): Change the output format and coerce time stamps to POSIXct format
coa_dat <- coa(mat = detection_matrix_by_id[[1]], xy = xy, output = "data.frame")
utils::str(coa_dat)
#> 'data.frame':	255 obs. of  3 variables:
#>  $ timestamp: POSIXct, format: "2016-03-17 01:00:00" "2016-03-21 01:00:00" ...
#>  $ x        : num  709191 709276 709276 707542 705754 ...
#>  $ y        : num  6253067 6253117 6253117 6267727 6267071 ...

#### Example (3): Implement the algorithm on a cluster
# This will only be faster for very large detection time series.
if (flapper_run_parallel) {
  coa_mat <- coa(
    mat = detection_matrix_by_id[[1]],
    xy = xy,
    cl = parallel::makeCluster(2L)
  )
}