From 5c85562ed0efa3a82a80c2a40a7e898bbfcaab4d Mon Sep 17 00:00:00 2001 From: Henrik Baktoft Date: Wed, 10 Feb 2021 15:52:25 +0100 Subject: [PATCH] v1.2.4 (#34) * bug fix re BIs in getToaYaps() & insert mandatory checkInp() in runYaps() * redo to make getToaYaps() backwards comp * robustify tmb using bounds - EXPERIMENTAL * relax pre-flight checks for ping_type='sbi' * v1.2.3.9005 docs and examples * reduce track length in example to run faster * reduce track length in example to run faster * bump version * v1.2.4 - CRAN --- .Rbuildignore | 1 + .gitignore | 2 + .travis.yml | 1 - DESCRIPTION | 12 +- NEWS.md | 17 ++- R/alignBurstSeq.R | 6 +- R/applySync.R | 6 +- R/checkInp.R | 13 +- R/checkInpSync.R | 4 +- R/data.R | 2 +- R/fineTuneSyncModel.R | 2 +- R/getBbox.R | 2 +- R/getInp.R | 34 +++++ R/getInpSync.R | 75 +++++++++++ R/getSyncModel.R | 95 ++++++++++++++ R/getToaYaps.R | 12 +- R/plotBbox.R | 1 + R/plotYaps.R | 1 + R/prepFiles.R | 3 +- R/prepTmb.R | 35 +---- R/runYaps.R | 58 ++++++--- R/simTrack.R | 10 +- R/syncGetters.R | 169 ------------------------- R/syncPlotters.R | 5 +- R/tempToSs.R | 1 + R/testYaps.R | 30 ++--- README.Rmd | 4 +- README.md | 9 +- cran-comments.md | 42 ------ man/alignBurstSeq.Rd | 11 +- man/applySync.Rd | 31 +++-- man/checkInp.Rd | 31 +++-- man/checkInpSync.Rd | 33 +++-- man/dat_align.Rd | 14 +- man/examples/example-alignBurstSeq.R | 3 - man/examples/example-bbox.R | 2 - man/examples/example-syncModelPlots.R | 8 +- man/examples/example-yaps_sim.R | 7 +- man/examples/example-yaps_ssu1.R | 22 ++-- man/fineTuneSyncModel.Rd | 110 ++-------------- man/getBbox.Rd | 6 +- man/getInp.Rd | 95 +++++++++++++- man/getInpSync.Rd | 39 +++--- man/getSyncCoverage.Rd | 96 +++++++++++++- man/getSyncModel.Rd | 37 +++--- man/getToaYaps.Rd | 31 +++-- man/plotBbox.Rd | 5 +- man/plotSyncModelCheck.Rd | 13 +- man/plotSyncModelHydros.Rd | 11 +- man/plotSyncModelResids.Rd | 11 +- man/plotYaps.Rd | 3 + man/prepDetections.Rd | 5 +- man/runYaps.Rd | 50 +++++--- man/simHydros.Rd | 9 +- man/simTelemetryTrack.Rd | 9 +- man/simToa.Rd | 7 +- man/simTrueTrack.Rd | 9 +- man/ssu1.Rd | 46 +++---- man/tempToSs.Rd | 3 + man/testYaps.Rd | 29 +++-- tests/testthat/sync_model_f1_ref.RData | Bin 31106 -> 30987 bytes tests/testthat/sync_model_ref.RData | Bin 31296 -> 31178 bytes 62 files changed, 808 insertions(+), 630 deletions(-) create mode 100644 R/getInp.R create mode 100644 R/getInpSync.R create mode 100644 R/getSyncModel.R delete mode 100644 cran-comments.md diff --git a/.Rbuildignore b/.Rbuildignore index 5b1b354..e6719c2 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -15,3 +15,4 @@ ^codecov\.yml$ ^\.travis\.yml$ ^cran-comments\.md$ +^CRAN-RELEASE$ diff --git a/.gitignore b/.gitignore index b0237dc..9bb2945 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ inst/doc debug.log README.html +cran-comments.md +CRAN-RELEASE diff --git a/.travis.yml b/.travis.yml index 44aeefc..b55a40f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,3 @@ addons: apt: packages: - libgit2-dev - \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 5048fac..6ac3895 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,21 +1,23 @@ Package: yaps Title: Track Estimation using YAPS (Yet Another Positioning Solver) -Version: 1.2.3 +Version: 1.2.4 Authors@R: c( person("Henrik", "Baktoft", email = "hba@aqua.dtu.dk", role = c("cre", "aut"), comment=c(ORCID = "0000-0002-3644-4960")), - person("Karl", "Gjelland", role=c("aut")), - person("Uffe H.", "Thygesen", role=c("aut")), - person("Finn", "Økland", role=c("aut")) + person("Karl", "Gjelland", role=c("aut"), comment=c(ORCID = "0000-0003-4036-4207")), + person("Uffe H.", "Thygesen", role=c("aut"), comment=c(ORCID = "0000-0002-4311-6324")), + person("Finn", "Økland", role=c("aut"), comment=c(ORCID = "0000-0002-1938-5460")) ) Description: Estimate tracks of animals tagged with acoustic transmitters. 'yaps' was introduced in 2017 as a transparent open-source tool to estimate positions of fish (and other aquatic animals) tagged with acoustic transmitters. Based on registrations of acoustic transmitters on hydrophones positioned in a fixed array, 'yaps' enables users to synchronize the collected data (i.e. correcting for drift in the internal clocks of the hydrophones/receivers) and subsequently to estimate tracks of the tagged animals. The paper introducing 'yaps' is available in open access at Baktoft, Gjelland, Økland & Thygesen (2017) . Also check out our cookbook with a completely worked through example at Baktoft, Gjelland, Økland, Rehage, Rodemann, Corujo, Viadero & Thygesen (2019) . Additional tutorials will eventually make their way onto the project website at . Depends: R (>= 3.5.0) License: GPL-3 Encoding: UTF-8 LazyData: true +Roxygen: list(markdown = TRUE) RoxygenNote: 7.1.1 LinkingTo: Rcpp, TMB, RcppEigen Imports: circular, cowplot, data.table, ggplot2, ggrepel, nloptr, plyr, Rcpp, reshape2, splusTimeSeries, stats, tictoc, TMB, viridis, zoo Suggests: - covr, + caTools, + covr, knitr, rmarkdown, testthat (>= 2.1.0), diff --git a/NEWS.md b/NEWS.md index 8f14676..f21ca2c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,21 @@ +# yaps v1.2.4 + +## New stuff +* Now on CRAN +* More checks in checkInp() to catch typical errors in format of inp. +* EXPERIMENTAL Attempt to robustify runYaps() - use with care. + +## Bug fixes +* Fix bug in getToaYaps() re number of empty pings. +* Docs and examples fixed to meet requirements. +* Make getToaYaps() aware of pingType + + # yaps v1.2.3 ## New stuff -* Moved example data `hald` to an external package with yaps example data `yapsdata`. Available from github using devtools::install_github('baktoft/yapsdata') -* Lots of examples and tests added +* Moved example data `hald` to an external package with yaps example data `yapsdata`. Available from github using devtools::install_github('baktoft/yapsdata'). +* Lots of examples and tests added. # yaps v1.2.2 diff --git a/R/alignBurstSeq.R b/R/alignBurstSeq.R index 02a9e4d..5bf465b 100644 --- a/R/alignBurstSeq.R +++ b/R/alignBurstSeq.R @@ -8,8 +8,8 @@ #' @param seq_lng_min Minimum length of sequence of consecutive pings to use for the alignment. Finds first occurence of sequence of this length in the data and compare to the known burst sequence #' @param rbi_min,rbi_max Minimum and maximum burst interval of the transmitter. Used to identify sequence of consecutive pings in the data #' @param plot_diag Logical indicating if visual diagnosis plots should be created. -#' return data.table like input, but with extra columns seq_ping_idx and seq_epo #' @export +#' @return `data.table` like the input `synced_dat`, but with extra columns seq_ping_idx and seq_epo #' @example man/examples/example-alignBurstSeq.R alignBurstSeq <- function(synced_dat, burst_seq, seq_lng_min=10, rbi_min, rbi_max, plot_diag=TRUE){ burst_seq_dt <- data.table::data.table(bi=burst_seq) @@ -52,12 +52,14 @@ alignBurstSeq <- function(synced_dat, burst_seq, seq_lng_min=10, rbi_min, rbi_ma # plot if plot_diag == TRUE if(plot_diag){ + oldpar <- par(no.readonly = TRUE) + on.exit(par(oldpar)) + par(mfrow=c(1,2)) plot(log(seq_diffs)) points(log(seq_diffs[seq_fix_idx]) ~ seq_fix_idx, col="red", pch=20, cex=2) plot(synced_dat[, eposync - seq_epo] ~ synced_dat$ts, pch=".") - par(mfrow=c(1,1)) } return(synced_dat) diff --git a/R/applySync.R b/R/applySync.R index 5d4cffd..d13d6df 100644 --- a/R/applySync.R +++ b/R/applySync.R @@ -1,10 +1,12 @@ #' Apply sync model to toa matrix to obtain synced data +#' #' @param toa Object containing data to be synchronized. Typically a `data.table` as e.g. `ssu1$detections`, but can also be a matrix dim=(n_ping, n_hydo). #' @param hydros data.table formatted as `ssu1$hydros` #' @param sync_model Synchronization model obtained using `getSyncModel()` -#' @example man/examples/example-yaps_ssu1.R - +#' #' @export +#' @return A `data.table` with the now synchronized time-of-arrivals in column `eposync`. +#' @example man/examples/example-yaps_ssu1.R applySync <- function(toa, hydros="", sync_model){ if(is.matrix(toa)) {type <- "toa_matrix" } else if(data.table::is.data.table(toa)) {type <- "detections_table"} diff --git a/R/checkInp.R b/R/checkInp.R index 40bdfe6..f6f6232 100644 --- a/R/checkInp.R +++ b/R/checkInp.R @@ -2,18 +2,27 @@ #' #' @param inp Object obtained using `getInp()` #' @export +#' @return No return value, but prints errors/warnings if issues with `inp` is detected. #' @example man/examples/example-yaps_ssu1.R checkInp <- function(inp){ + + # check that all BIs are in range of values in the model + # only relevant for ping_types 'rbi' and 'pbi'? + if(inp$datTmb$pingType != 'sbi'){ + stopifnot(inp$datTmb$rbi_min <= min(diff(inp$params$top))) + stopifnot(inp$datTmb$rbi_max >= max(diff(inp$params$top))) + } stopifnot(ncol(inp$datTmb$toa) == inp$datTmb$np) stopifnot(nrow(inp$datTmb$toa) == inp$datTmb$nh) + stopifnot(dim(inp$datTmb$H)[2] == 3) + # if z_vec != NULL if(inp$datTmb$how_3d != 'none'){ - stopifnot(dim(inp$datTmb$H)[2] == 3) stopifnot(length(inp$datTmb$z_vec) == inp$datTmb$np) } - print("checkInp passed!") + print("Pre-flight checkInp() passed!") } \ No newline at end of file diff --git a/R/checkInpSync.R b/R/checkInpSync.R index 3e61c57..a07dad0 100644 --- a/R/checkInpSync.R +++ b/R/checkInpSync.R @@ -3,6 +3,7 @@ #' @inheritParams getInpSync #' @param inp_sync Object obtained using `getInpSync()` #' @export +#' @return No return value, but prints errors/warnings if issues with `inp_sync` is detected. #' @example man/examples/example-yaps_ssu1.R checkInpSync <- function(inp_sync, silent_check){ # speed of sound stuff @@ -34,7 +35,6 @@ checkInpSync <- function(inp_sync, silent_check){ } else if(!silent_check & min(sync_coverage$N) < 50) { cat("NOTE: At least one hydro has less than 50 pings in an offset_idx - try getSyncCoverage(inp_sync, plot=TRUE) for visual\n and rerun getInpSync() with increased keep_rate\n") } - return(sync_coverage) } #' Quick overview to check if all hydros have enough data within each offset period. @@ -42,6 +42,8 @@ checkInpSync <- function(inp_sync, silent_check){ #' @inheritParams checkInpSync #' @param plot Logical indicating whether to plot a visual or not. #' @export +#' @return A data.table containing number of pings included in each hydro x offset combination. +#' @example man/examples/example-yaps_ssu1.R getSyncCoverage <- function(inp_sync, plot=FALSE){ toa <- inp_sync$dat_tmb_sync$toa nh <- ncol(toa) diff --git a/R/data.R b/R/data.R index f8a0bc7..68e438c 100644 --- a/R/data.R +++ b/R/data.R @@ -19,7 +19,7 @@ #' \item ts Timestamp of detection in POSIXct(). #' \item tag ID of detected tag. #' \item epo Timestamp as number of seconds since Unix epoch. Can be obtained using as.numeric(ts). -#' \item frac Sub-second part of detection timestamp in fractions of second [0-1]. +#' \item frac Sub-second part of detection timestamp in fractions of second (0-1). #' \item serial Serial number of detecting hydrophone. Must match entry in data.table hydros. #' } #' } diff --git a/R/fineTuneSyncModel.R b/R/fineTuneSyncModel.R index 5ab04dd..1107e47 100644 --- a/R/fineTuneSyncModel.R +++ b/R/fineTuneSyncModel.R @@ -3,8 +3,8 @@ #' @param sync_model sync_model obtained using getSyncModel() #' @param eps_threshold Maximum value of residual measured in meter assuming speed of sound = 1450 m/s #' @param silent logical whether to make getSyncModel() silent -#' @example man/examples/example-yaps_ssu1.R #' @export +#' @return Fine tuned `sync_model`. See `?getSyncModel` for more info. #' @example man/examples/example-yaps_ssu1.R fineTuneSyncModel <- function(sync_model, eps_threshold, silent=TRUE){ # original inp_sync diff --git a/R/getBbox.R b/R/getBbox.R index 92c32da..67f3cdf 100644 --- a/R/getBbox.R +++ b/R/getBbox.R @@ -1,12 +1,12 @@ #' Get a standard bounding box to impose spatial constraints #' #' Standard is a rectangle based on coordinates of outer hydros +- the buffer in meters -#' Returns a vector of lenght 6: c(x_min, x_max, y_min, y_max, eps, pen). Limits are given in UTM coordinates. #' @param buffer Number of meters the spatial domain extends beyound the outer hydros. #' @param eps Specifies how well-defined the borders are (eps=1E-2 is very sharp, eps=100 is very soft). #' @param pen Specifies the penalty multiplier. #' @inheritParams getInp #' @export +#' @return Vector of lenght 6: c(x_min, x_max, y_min, y_max, eps, pen). Limits are given in UTM coordinates. #' @example man/examples/example-bbox.R getBbox <- function(hydros, buffer=5, eps=1E-3, pen=1){ x_min <- hydros[which.min(hydros$hx), hx] - buffer diff --git a/R/getInp.R b/R/getInp.R new file mode 100644 index 0000000..6fc5994 --- /dev/null +++ b/R/getInp.R @@ -0,0 +1,34 @@ +#' Get prepared inp-object for use in TMB-call +#' +#' Wrapper-function to compile a list of input needed to run TMB +#' @param hydros Dataframe from simHydros() or Dataframe with columns hx and hy containing positions of the receivers. Translate the coordinates to get the grid centre close to (0;0). +#' @param toa TOA-matrix: matrix with receivers in rows and detections in columns. Make sure that the receivers are in the same order as in hydros, and that the matrix is very regular: one ping per column (inlude empty columns if a ping is not detected). +#' @param E_dist Which distribution to use in the model - "Gaus" = Gaussian, "Mixture" = mixture of Gaussian and t or "t" = pure t-distribution +#' @param n_ss Number of soundspeed estimates: one estimate per hour is usually enough +#' @param pingType Type of transmitter to simulate - either stable burst interval ('sbi'), random burst interval ('rbi') or random burst interval but where the random sequence is known a priori +#' @param rbi_min,rbi_max Minimum and maximum BI for random burst interval transmitters +#' @param sdInits If >0 initial values will be randomized around the normally fixed value using rnorm(length(inits), mean=inits, sd=sdInits) +#' @param ss_data_what What speed of sound (ss) data to be used. Default ss_data_what='est': ss is estimated by the model. Alternatively, if ss_data_what='data': ss_data must be provided and length(ss_data) == ncol(toa) +#' @param ss_data Vector of ss-data to be used if ss_data_what = 'est'. Otherwise ss_data <- 0 (default) +#' @param biTable Table of known burst intervals. Only used when pingType == "pbi". Default=NULL +#' @param z_vec Vector of known depth values (positive real). Default=NULL is which case no 3D is assumed. If z_vec = "est" depth will be estimated. +#' @param bbox Spatial constraints in the form of a bounding box. See ?getBbox for details. + +#' @return List of input data ready for use in `runYaps()` +#' @export +#' @example man/examples/example-yaps_ssu1.R +getInp <- function(hydros, toa, E_dist, n_ss, pingType, sdInits=1, rbi_min=0, rbi_max=0, ss_data_what='est', ss_data=0, biTable=NULL, z_vec=NULL, bbox=NULL){ + stopifnot(pingType %in% c('sbi', 'pbi', 'rbi')) + inp_params <- getInpParams(hydros, toa, pingType) + datTmb <- getDatTmb(hydros, toa, E_dist, n_ss, pingType, rbi_min, rbi_max, ss_data_what, ss_data, biTable, inp_params, z_vec, bbox) + params <- getParams(datTmb) + inits <- getInits(datTmb, sdInits) + return(list( + datTmb = datTmb, + params= params, + inits = inits, + inp_params = inp_params + ) + ) +} + diff --git a/R/getInpSync.R b/R/getInpSync.R new file mode 100644 index 0000000..6b5ab99 --- /dev/null +++ b/R/getInpSync.R @@ -0,0 +1,75 @@ +#' Get object inp for synchronization +#' +#' @param sync_dat List containing data.tables with hydrophone information and detections. See e.g. `?ssu1` for example +#' @param max_epo_diff Sets the upper threshold for differences in TOA of sync tags. Best parameter value depends on burst rate of sync tags and how far apart the internal clocks of the hydros are prior to synchronization. A bit less than half of minimum sync tag burst rate is a good starting choice. +#' @param min_hydros Sets the lower threshold of how many hydrophones need to detect each sync tag ping in order to be included in the sync process. Should be as high as possible while observing that all hydrosphones are contributing. If too low, isolated hydrophones risk falling out completely. Future versions will work towards automising this. +#' @param time_keeper_idx Index of the hydrophone to use as time keeper. Could e.g. be the one with smallest overall clock-drift. +#' @param fixed_hydros_idx Vector of hydro idx's for all hydrophones where the position is assumed to be known with adequate accuracy and precission. Include as many as possible as fixed hydros to reduce overall computation time and reduce overall variability. As a bare minimum two hydros need to be fixed, but we strongly advice to use more than two. +#' @param n_offset_day Specifies the number of hydrophone specific quadratic polynomials to use per day. For PPM based systems, 1 or 2 is often adeqaute. +#' @param n_ss_day Specifies number of speed of sound to estimate per day if no ss data is supplied. It is recommended to use logged water temperature instead. However, estimating SS gives an extra option for sanity-checking the final sync-model. +#' @param ss_data_what Indicates whether to estimate ("est") speed of sound or to use data based on logged water temperature ("data"). +#' @param ss_data data.table containing timestamp and speed of sound for the entire period to by synchronised. Must contain columns 'ts' (POSIXct timestamp) and 'ss' speed of sound in m/s (typical values range 1400 - 1550). +#' @param keep_rate Syncing large data sets can take a really long time. However, there is typically an excess number of sync tag detections +#' and a sub-sample is typically enough for good synchronization. +#' This parameter EITHER specifies a proportion (0-1) of data to keep when sub-sampling +#' OR (if keep_rate > 10) number of pings (approximate) to keep in each hydro X offset_idx combination if enough exists. +#' @param excl_self_detect Logical whether to excluded detections of sync tags on the hydros they are co-located with. Sometimes self detections can introduce excessive residuals in the sync model in which case they should be excluded. +#' @param lin_corr_coeffs Matrix of coefficients used for pre-sync linear correction. `dim(lin_corr_coeffs)=(#hydros, 2)`. +#' @param silent_check Logical whether to get output from `checkInpSync()`. Default is FALSE +#' +#' @export +#' @return List of input data ready for use in `getSyncModel()` +#' @example man/examples/example-yaps_ssu1.R +getInpSync <- function(sync_dat, max_epo_diff, min_hydros, time_keeper_idx, fixed_hydros_idx, n_offset_day, n_ss_day, keep_rate=1, excl_self_detect=TRUE, lin_corr_coeffs=NA, ss_data_what="est", ss_data=c(0), silent_check=FALSE){ + if(length(unique(sync_dat$hydros$serial)) != nrow(sync_dat$hydros)){ + print(sync_dat$hydros[, .N, by=serial][N>=2]) + stop("ERROR: At least one hydrophone serial number is used more than once in sync_dat$hydros!\n") + } + + if(keep_rate <=0 | (keep_rate > 1 & keep_rate < 10) | (keep_rate >= 10 & keep_rate %% 1 != 0)){ + stop("ERROR: Invalid keep_rate! Must be either ]0;1] or integer >= 10\n") + } + + sync_dat <- appendDetections(sync_dat) + + if(is.na(lin_corr_coeffs[1])){ + lin_corr_coeffs <- matrix(0, nrow=nrow(sync_dat$hydros), ncol=2, byrow=TRUE) + } + + sync_dat <- applyLinCorCoeffsInpSync(sync_dat, lin_corr_coeffs) + + T0 <- min(sync_dat$detections$epo) + + inp_H_info <- getInpSyncHInfo(sync_dat) + + inp_toa_list_all <- getInpSyncToaList(sync_dat, max_epo_diff, min_hydros, excl_self_detect) + fixed_hydros_vec <- getFixedHydrosVec(sync_dat, fixed_hydros_idx) + offset_vals_all <- getOffsetVals(inp_toa_list_all, n_offset_day) + inp_toa_list <- getDownsampledToaList(inp_toa_list_all, offset_vals_all, keep_rate) + offset_vals <- getOffsetVals(inp_toa_list, n_offset_day) + ss_vals <- getSsVals(inp_toa_list, n_ss_day) + if(ss_data_what == "data"){ + ss_data_vec <- getSsDataVec(inp_toa_list, ss_data) + } else { + ss_data_vec <- c(0) + } + + dat_tmb_sync <- getDatTmbSync(sync_dat, time_keeper_idx, inp_toa_list, fixed_hydros_vec, offset_vals, ss_vals, inp_H_info, T0, ss_data_what, ss_data_vec) + params_tmb_sync <- getParamsTmbSync(dat_tmb_sync, ss_data_what) + if(ss_data_what == "est"){ + random_tmb_sync <- c("TOP", "OFFSET", "SLOPE1", "SLOPE2", "SS", "TRUE_H") + } else { + random_tmb_sync <- c("TOP", "OFFSET", "SLOPE1", "SLOPE2", "TRUE_H") + } + # inits_tmb_sync <- c(3, rep(-3,dat_tmb_sync$nh)) + inits_tmb_sync <- c(-3) + inp_params <- list(toa=inp_toa_list$toa, T0=T0, Hx0=inp_H_info$Hx0, Hy0=inp_H_info$Hy0, offset_levels=offset_vals$offset_levels, + ss_levels=ss_vals$ss_levels, max_epo_diff=max_epo_diff, hydros=sync_dat$hydros, + lin_corr_coeffs=lin_corr_coeffs, min_hydros=min_hydros, ss_data=ss_data + ) + + inp_sync <- list(dat_tmb_sync=dat_tmb_sync, params_tmb_sync=params_tmb_sync, random_tmb_sync=random_tmb_sync, inits_tmb_sync=inits_tmb_sync, inp_params=inp_params) + inp_sync$inp_params$sync_coverage <- checkInpSync(inp_sync, silent_check) + return(inp_sync) + +} diff --git a/R/getSyncModel.R b/R/getSyncModel.R new file mode 100644 index 0000000..cf2179d --- /dev/null +++ b/R/getSyncModel.R @@ -0,0 +1,95 @@ +#' Get sync model from inp_sync object obtained by `getInpSync()` +#' +#' @param inp_sync Input data prepared for the sync model using `getInpSync()` +#' @param silent Keep TMB quiet +#' @param fine_tune Logical. Whether to re-run the sync model excluding residual outliers. **Deprecated** use fineTuneSyncModel() instead. +#' @param max_iter Max number of iterations to run TMB. Default=100 seems to work in most cases. +#' @param tmb_smartsearch Logical whether to use the TMB smartsearch in the inner optimizer (see `?TMB::MakeADFun` for info). Default and original implementation is TRUE. However, there seems to be an issue with some versions of `Matrix` that requires `tmb_smartsearch=FALSE`. +#' +#' @export +#' @return List containing relevant data constituting the `sync_model` ready for use in `fineTuneSyncModel()` if needed or in `applySync()` +#' @example man/examples/example-yaps_ssu1.R +getSyncModel <- function(inp_sync, silent=TRUE, fine_tune=FALSE, max_iter=100, tmb_smartsearch=TRUE){ + inp_sync$inp_params$tmb_smartsearch <- tmb_smartsearch + inp_sync$inp_params$max_iter <- max_iter + + dat_tmb <- inp_sync$dat_tmb_sync + params <- inp_sync$params_tmb_sync + random <- inp_sync$random_tmb_sync + inits <- inp_sync$inits_tmb_sync + inp_params <- inp_sync$inp_params + + cat(paste0(Sys.time(), " \n")) + cat(". Running optimization of the sync model. Please be patient - this can take a long time. \n") + if(fine_tune){cat(".... fine tuning is enabled, but is getting deprecated in future version. Consider to use the function fineTuneSyncModel() instead. See ?fineTuneSyncModel for info. \n")} + + tictoc::tic("Fitting sync model: ") + opt <- c() + pl <- c() + plsd <- c() + obj <- c() + + tictoc::tic() + obj <- c() + opt <- c() + report <- c() + gc() + + # config(DLL="yaps_sync") + # ## Reduce memory peak of a parallel model by creating tapes in serial + # config(tape.parallel=0, DLL="yaps_sync") + obj <- TMB::MakeADFun(data = dat_tmb, parameters = params, random = random, DLL = "yaps", inner.control = list(maxit = max_iter), silent=silent) + obj$fn(obj$par) + + if(!tmb_smartsearch){ + TMB::newtonOption(obj, smartsearch=FALSE) + } + + + if(silent){ + # opt <- suppressWarnings(stats::nlminb(inits,obj$fn,obj$gr)) + opt <- suppressWarnings(stats::nlminb(inits,obj$fn,obj$gr, lower=c(-10), upper=c(-2))) + } else { + opt <- stats::nlminb(inits,obj$fn,obj$gr, lower=c(-10), upper=c(-2)) + # opt <- stats::nlminb(inits,obj$fn,obj$gr) + } + + pl <- obj$env$parList() # List of estimates + obj_val <- opt$objective + cat(paste0(".. ", Sys.time()), " \n") + cat(".... obj = ", obj_val, " \n") + report <- obj$report() + + crazy_outliers <- which(abs(report$eps_toa)*1450 > 10000) + fine_outliers <- which(abs(report$eps_toa)*1450 > 1000) + if(length(crazy_outliers > 0)){ + cat(".... some extreme outliers potentially affecting the model where identified \n Consider to run fineTuneSyncModel(sync_model, eps_threshold=10000). See ?fineTuneSyncModel for more info. \n") + # dat_tmb$toa_offset[crazy_outliers] <- NA + } else if(fine_tune){ + cat(".... fine tuning is enabled, but is deprecated. Use the function fineTuneSyncModel() instead. See ?fineTuneSyncModel for info. \n") + # dat_tmb$toa_offset[fine_outliers] <- NA + } + + tictoc::toc() + + jointrep <- try(TMB::sdreport(obj, getJointPrecision=TRUE), silent=silent) + param_names <- rownames(summary(jointrep)) + sds <- summary(jointrep)[,2] + summ <- data.frame(param=param_names, sd=sds) + plsd <- split(summ[,2], f=summ$param) + + pl$TRUE_H[,1] <- pl$TRUE_H[,1] + inp_params$Hx0 + pl$TRUE_H[,2] <- pl$TRUE_H[,2] + inp_params$Hy0 + eps_long <- getEpsLong(report, pl, inp_sync) + + offset_nas <- which(pl$OFFSET == 0) + pl$OFFSET[offset_nas] <- NA + pl$SLOPE1[offset_nas] <- NA + pl$SLOPE2[offset_nas] <- NA + + cat("Sync model done \n") + cat("Consider saving the sync model for later use - e.g. save(sync_model, file='path_to_sync_save'). \n") + + return(list(pl=pl, plsd=plsd, report=report, obj_val=obj_val, eps_long=eps_long, inp_synced=inp_sync)) +} + diff --git a/R/getToaYaps.R b/R/getToaYaps.R index b89bc4f..3d48619 100644 --- a/R/getToaYaps.R +++ b/R/getToaYaps.R @@ -3,9 +3,15 @@ #' @param synced_dat `data.table` containing synchronized data formatted as output from/or obtained using `applySync()` #' @inheritParams getInp #' @export +#' @return Matrix of time-of-arrivals. One coloumn per hydro, one row per ping. #' @example man/examples/example-yaps_ssu1.R -getToaYaps <- function(synced_dat, hydros, rbi_min, rbi_max){ - +getToaYaps <- function(synced_dat, hydros, rbi_min, rbi_max, pingType=NULL){ + if(is.null(pingType)){ + cat("WARNING: pingType not specified in getToaYaps() - will assume 'rbi'. This will become a fatal error in later versions.\n") + pingType <- 'rbi' + } + stopifnot(pingType %in% c('sbi', 'pbi', 'rbi')) + # remove NAs in eposync synced_dat <- synced_dat[!is.na(eposync)] # remove multipaths... @@ -73,7 +79,7 @@ getToaYaps <- function(synced_dat, hydros, rbi_min, rbi_max){ } else { pings[, next_ping_too_late := diff > rbi_max+.1] } - if(rbi_max > 15){ ### USE PING_TYPE INSTEAD!!!! + if(pingType != 'sbi'){ pings[next_ping_too_late==TRUE, ping2next:=ping2next+round(diff/rbi_max)] } else { pings[next_ping_too_late==TRUE, ping2next:=round(diff/rbi_max)] # the line above puts in an extra pang for pingType = "sbi" diff --git a/R/plotBbox.R b/R/plotBbox.R index 5c897f2..84cb3f3 100644 --- a/R/plotBbox.R +++ b/R/plotBbox.R @@ -1,6 +1,7 @@ #' Graphical representation of spatial constraints #' @inheritParams getInp #' @export +#' @return No return value, called to plot graphic. #' @example man/examples/example-bbox.R plotBbox <- function(hydros, bbox){ Var1 <- Var2 <- NULL diff --git a/R/plotYaps.R b/R/plotYaps.R index 5db2436..f6a0544 100644 --- a/R/plotYaps.R +++ b/R/plotYaps.R @@ -5,6 +5,7 @@ #' @param xlim,ylim Optional vectors of length 2 to set xlim and/or ylim. #' @param main Title of plot - optional. #' @export +#' @return No return value, called to plot graphics. #' @example man/examples/example-plotYaps.R plotYaps <- function(yaps_out, type="map", xlim=NULL, ylim=NULL, main=NULL){ inp <- yaps_out$inp diff --git a/R/prepFiles.R b/R/prepFiles.R index 32f93bb..a0f3dae 100644 --- a/R/prepFiles.R +++ b/R/prepFiles.R @@ -2,8 +2,9 @@ #' @param raw_dat Data file from vendor supplied software #' @param type Type of the vendor file. Currently only 'vemco_vue' is supported. #' @export +#' @return `data.table` containing detections extracted from manufacturer data file. #' @examples \dontrun{ -#' prepped_detections <- prepDetection("path-to-raw-data-file", type="vemco_vue") +#' prepped_detections <- prepDetections("path-to-raw-data-file", type="vemco_vue") #' } prepDetections <- function(raw_dat, type){ detections <- data.table::data.table() diff --git a/R/prepTmb.R b/R/prepTmb.R index 3ecb8f7..45f6c12 100644 --- a/R/prepTmb.R +++ b/R/prepTmb.R @@ -1,36 +1,3 @@ -#' Get prepared inp-object for use in TMB-call -#' -#' Wrapper-function to compile a list of input needed to run TMB -#' @param hydros Dataframe from simHydros() or Dataframe with columns hx and hy containing positions of the receivers. Translate the coordinates to get the grid centre close to (0;0). -#' @param toa TOA-matrix: matrix with receivers in rows and detections in columns. Make sure that the receivers are in the same order as in hydros, and that the matrix is very regular: one ping per column (inlude empty columns if a ping is not detected). -#' @param E_dist Which distribution to use in the model - "Gaus" = Gaussian, "Mixture" = mixture of Gaussian and t or "t" = pure t-distribution -#' @param n_ss Number of soundspeed estimates: one estimate per hour is usually enough -#' @param pingType Type of transmitter to simulate - either stable burst interval ('sbi'), random burst interval ('rbi') or random burst interval but where the random sequence is known a priori -#' @param rbi_min,rbi_max Minimum and maximum BI for random burst interval transmitters -#' @param sdInits If >0 initial values will be randomized around the normally fixed value using rnorm(length(inits), mean=inits, sd=sdInits) -#' @param ss_data_what What speed of sound (ss) data to be used. Default ss_data_what='est': ss is estimated by the model. Alternatively, if ss_data_what='data': ss_data must be provided and length(ss_data) == ncol(toa) -#' @param ss_data Vector of ss-data to be used if ss_data_what = 'est'. Otherwise ss_data <- 0 (default) -#' @param biTable Table of known burst intervals. Only used when pingType == "pbi". Default=NULL -#' @param z_vec Vector of known depth values (positive real). Default=NULL is which case no 3D is assumed. If z_vec = "est" depth will be estimated. -#' @param bbox Spatial constraints in the form of a bounding box. See ?getBbox for details. - -#' @return List of input data ready for use in TMB-call -#' @export -getInp <- function(hydros, toa, E_dist, n_ss, pingType, sdInits=1, rbi_min=0, rbi_max=0, ss_data_what='est', ss_data=0, biTable=NULL, z_vec=NULL, bbox=NULL){ - inp_params <- getInpParams(hydros, toa, pingType) - datTmb <- getDatTmb(hydros, toa, E_dist, n_ss, pingType, rbi_min, rbi_max, ss_data_what, ss_data, biTable, inp_params, z_vec, bbox) - params <- getParams(datTmb) - inits <- getInits(datTmb, sdInits) - return(list( - datTmb = datTmb, - params= params, - inits = inits, - inp_params = inp_params - ) - ) -} - - #' Internal function - get data for input to TMB #' #' Compile data for input to TMB. @@ -72,7 +39,7 @@ getDatTmb <- function(hydros, toa, E_dist, n_ss, pingType, rbi_min, rbi_max, ss_ if(is.null(z_vec)){ how_3d <- 'none' z_vec <- c(1) - } else if(z_vec == "est") { + } else if(z_vec[1] == "est") { how_3d <- 'est' z_vec <- c(1) } else { diff --git a/R/runYaps.R b/R/runYaps.R index 5d91b54..7d8ffd6 100644 --- a/R/runYaps.R +++ b/R/runYaps.R @@ -1,16 +1,37 @@ #' Function to run TMB to estimate track #' -#' @param inp inp-object obtained from getInp() -#' @param maxIter Sets inner.control(maxit) of the tmb-call. Increase if model is not converging. +#' @param inp inp-object obtained from `getInp()` +#' @param maxIter Sets `inner.control(maxit)` of the TMB-call. Increase if model is not converging. #' @param getPlsd,getRep Whether or not to get sd estimates (plsd=TRUE) and reported values (getRep=TRUE). #' @param silent Logical whether to keep the optimization quiet. -#' @param opt_fun Which optimization function to use. Default is 'nlminb' - alternative is 'nloptr' (experimental!). If using 'nloptr', `opt_controls` must be specified. -#' @param opt_controls List of controls passed to optimization function. For instances, tolerances such as x.tol=1E-8. If opt_fun = 'nloptr', `opt_controls` must be a list formatted appropriately. For instance: opt_controls <- list(algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) ). See `?nloptr` and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in `nloptr` require bounded parameters - see `bounds`. -#' @param bounds List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) ). -#' @param tmb_smartsearch Logical whether to use the TMB smartsearch in the inner optimizer (see ?TMB::MakeADFun for info). Default and original implementation is TRUE. However, there seems to be an issue with Matrix v1.3.2 that requires tmb_smartsearch=FALSE. -#' @example man/examples/example-yaps_ssu1.R +#' @param opt_fun Which optimization function to use. Default is `opt_fun = 'nlminb'` - alternative is `opt_fun = 'nloptr'` (experimental!). If using nloptr, `opt_controls` must be specified. +#' @param opt_controls List of controls passed to optimization function. For instances, tolerances such as `x.tol=1E-8`. \cr +#' If `opt_fun = 'nloptr'`, `opt_controls` must be a list formatted appropriately. For instance: \cr +#' `opt_controls <- list( algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) )`. \cr +#' See `?nloptr` and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in `nloptr` require bounded parameters - see `bounds`. +#' @param bounds List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, `bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) )`. +#' @param tmb_smartsearch Logical whether to use the TMB smartsearch in the inner optimizer (see `?TMB::MakeADFun` for info). Default and original implementation is TRUE. However, there seems to be an issue with recent versions of `Matrix` that requires `tmb_smartsearch=FALSE`. +#' #' @export +#' +#' @return List containing results of fitting `yaps` to the data. +#' \describe{ +#' \item{pl}{List containing all parameter estimates.} +#' \item{plsd}{List containing standard errors of parameter estimates.} +#' \item{rep}{List containing `mu_toa`.} +#' \item{obj}{Numeric obj value of the fitted model obtained using `obj$fn()`.} +#' \item{inp}{List containing the `inp` object used in `runYaps()`. See `?getInp` for further info.} +#' \item{conv_status}{Integer convergence status.} +#' \item{conv_message}{Text version of convergence status.} +#' \item{track}{A data.table containing the estimated track including time-of-ping (top), standard errors and number of hydros detecting each ping (nobs).} +#' } +#' +#' @example man/examples/example-yaps_ssu1.R runYaps <- function(inp, maxIter=1000, getPlsd=TRUE, getRep=TRUE, silent=TRUE, opt_fun='nlminb', opt_controls=list(), bounds=list(), tmb_smartsearch=TRUE){ + + # making sure inp is correct... + checkInp(inp) + nobs <- z <- z_sd <- NULL print("Running yaps...") random <- c("X", "Y", "top") @@ -37,6 +58,15 @@ runYaps <- function(inp, maxIter=1000, getPlsd=TRUE, getRep=TRUE, silent=TRUE, o obj$fn(obj$par) TMB::newtonOption(obj, smartsearch=FALSE) } + + if( !is.null(opt_controls[['use_bounds']])){ + lower <- opt_controls[['lower']] + upper <- opt_controls[['upper']] + opt_controls <- list() + } else { + lower <- -Inf + upper <- Inf + } if(opt_fun == 'nloptr'){ opts <- opt_controls @@ -48,18 +78,12 @@ runYaps <- function(inp, maxIter=1000, getPlsd=TRUE, getRep=TRUE, silent=TRUE, o } else if(opt_fun == 'nlminb'){ control_list <- opt_controls - if(!silent){ - # tictoc::tic() - opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list) - # tictoc::toc() - - # tictoc::tic() - # opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list, lower=c(-10,-10, -10, -10, -10), upper=c(2, 2, 2, 2, -2)) - # opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list, lower=c(-10,-10, -10, -10, -10), upper=c(2, 2, 2, 2, -2)) - # tictoc::toc() + # opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list) + # opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list, lower=c(-50,-15, -100, -50, -20), upper= c(2, 2, 100, 2, -2)) + opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list, lower=lower, upper=upper) } else { - suppressWarnings(opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list)) + suppressWarnings(opt <- stats::nlminb(inp$inits,obj$fn,obj$gr, control = control_list, lower=lower, upper=upper)) } } diff --git a/R/simTrack.R b/R/simTrack.R index d92253b..6d11426 100644 --- a/R/simTrack.R +++ b/R/simTrack.R @@ -13,7 +13,7 @@ #' @param start_pos Specify the starting position of the track with c(x0, y0) #' @param ss Simulations model for Speed of Sound - defaults to 'rw' = RW-model. #' -#' @return Dataframe containing a simulated track +#' @return `data.frame` containing a simulated track #' @export #' @example man/examples/example-yaps_sim.R simTrueTrack <- function(model='rw', n, deltaTime=1, D=NULL, shape=NULL, scale=NULL, addDielPattern=TRUE, ss='rw', start_pos=NULL){ @@ -78,7 +78,7 @@ simTrueTrack <- function(model='rw', n, deltaTime=1, D=NULL, shape=NULL, scale=N #' @param sbi_mean,sbi_sd Mean and SD of burst interval when pingType = 'sbi' #' @inheritParams getInp #' -#' @return Data frame containing time of ping and true positions +#' @return `data.frame` containing time of ping and true positions #' @export #' @example man/examples/example-yaps_sim.R simTelemetryTrack <- function(trueTrack, pingType, sbi_mean=NULL, sbi_sd=NULL, rbi_min=NULL, rbi_max=NULL){ @@ -110,8 +110,9 @@ simTelemetryTrack <- function(trueTrack, pingType, sbi_mean=NULL, sbi_sd=NULL, r #' #' @param auto If TRUE, attempts to find a decent array configuration to cover the simulated true track. #' @param trueTrack Track obtained from simTrueTrack(). -#' @return Dataframe containing X and Y for hydros +#' #' @export +#' @return `data.frame` containing X and Y for hydros #' @example man/examples/example-yaps_sim.R simHydros <- function(auto=TRUE, trueTrack=NULL){ try(if(auto == TRUE & is.null(trueTrack)) stop("When auto is TRUE, trueTrack needs to be supplied")) @@ -138,8 +139,9 @@ simHydros <- function(auto=TRUE, trueTrack=NULL){ #' @param pMP Probability of multipath propagated signal 0-1 #' @param tempRes Temporal resolution of the hydrophone. PPM systems are typially 1/1000 sec. Other systems are as high as 1/19200 sec. #' @inheritParams getInp -#' @return List containing TOA matrix (toa) and matrix indicating, which obs are multipath (mp_mat) +#' #' @export +#' @return List containing TOA matrix (toa) and matrix indicating, which obs are multipath (mp_mat) #' @example man/examples/example-yaps_sim.R simToa <- function(telemetryTrack, hydros, pingType, sigmaToa, pNA, pMP, tempRes=NA){ #correct toa diff --git a/R/syncGetters.R b/R/syncGetters.R index acfb232..cf701e4 100644 --- a/R/syncGetters.R +++ b/R/syncGetters.R @@ -1,172 +1,3 @@ -#' Get sync model from inp_sync object obtained by getInpSync() -#' @param inp_sync Input data prepared for the sync model using `getInpSync()` -#' @param silent Keep TMB quiet -#' @param fine_tune Logical. Whether to re-run the sync model excluding residual outliers. Consider to use fineTuneSyncModel() instead. -#' @param max_iter Max number of iterations to run TMB. Default=100 seems to work in most cases. -#' @param tmb_smartsearch Logical whether to use the TMB smartsearch in the inner optimizer (see ?TMB::MakeADFun for info). Default and original implementation is TRUE. However, there seems to be an issue with Matrix v1.3.2 that requires tmb_smartsearch=FALSE. -#' @example man/examples/example-yaps_ssu1.R - -#' @export -getSyncModel <- function(inp_sync, silent=TRUE, fine_tune=FALSE, max_iter=100, tmb_smartsearch=TRUE){ - inp_sync$inp_params$tmb_smartsearch <- tmb_smartsearch - inp_sync$inp_params$max_iter <- max_iter - - dat_tmb <- inp_sync$dat_tmb_sync - params <- inp_sync$params_tmb_sync - random <- inp_sync$random_tmb_sync - inits <- inp_sync$inits_tmb_sync - inp_params <- inp_sync$inp_params - - cat(paste0(Sys.time(), " \n")) - cat(". Running optimization of the sync model. Please be patient - this can take a long time. \n") - if(fine_tune){cat(".... fine tuning is enabled, but is getting deprecated in this function. Consider to use the function fineTuneSyncModel() instead. See ?fineTuneSyncModel for info. \n")} - - tictoc::tic("Fitting sync model: ") - opt <- c() - pl <- c() - plsd <- c() - obj <- c() - - tictoc::tic() - obj <- c() - opt <- c() - report <- c() - gc() - - # config(DLL="yaps_sync") - # ## Reduce memory peak of a parallel model by creating tapes in serial - # config(tape.parallel=0, DLL="yaps_sync") - obj <- TMB::MakeADFun(data = dat_tmb, parameters = params, random = random, DLL = "yaps", inner.control = list(maxit = max_iter), silent=silent) - obj$fn(obj$par) - - if(!tmb_smartsearch){ - TMB::newtonOption(obj, smartsearch=FALSE) - } - - - if(silent){ - # opt <- suppressWarnings(stats::nlminb(inits,obj$fn,obj$gr)) - opt <- suppressWarnings(stats::nlminb(inits,obj$fn,obj$gr, lower=c(-10), upper=c(-2))) - } else { - opt <- stats::nlminb(inits,obj$fn,obj$gr, lower=c(-10), upper=c(-2)) - # opt <- stats::nlminb(inits,obj$fn,obj$gr) - } - - pl <- obj$env$parList() # List of estimates - obj_val <- opt$objective - cat(paste0(".. ", Sys.time()), " \n") - cat(".... obj = ", obj_val, " \n") - report <- obj$report() - - crazy_outliers <- which(abs(report$eps_toa)*1450 > 10000) - fine_outliers <- which(abs(report$eps_toa)*1450 > 1000) - if(length(crazy_outliers > 0)){ - cat(".... some extreme outliers potentially affecting the model where identified \n Consider to run fineTuneSyncModel(sync_model, eps_threshold=10000). See ?fineTuneSyncModel for more info. \n") - # dat_tmb$toa_offset[crazy_outliers] <- NA - } else if(fine_tune){ - cat(".... fine tuning is enabled, but is deprecated. Use the function fineTuneSyncModel() instead. See ?fineTuneSyncModel for info. \n") - # dat_tmb$toa_offset[fine_outliers] <- NA - } - - tictoc::toc() - - jointrep <- try(TMB::sdreport(obj, getJointPrecision=TRUE), silent=silent) - param_names <- rownames(summary(jointrep)) - sds <- summary(jointrep)[,2] - summ <- data.frame(param=param_names, sd=sds) - plsd <- split(summ[,2], f=summ$param) - - pl$TRUE_H[,1] <- pl$TRUE_H[,1] + inp_params$Hx0 - pl$TRUE_H[,2] <- pl$TRUE_H[,2] + inp_params$Hy0 - eps_long <- getEpsLong(report, pl, inp_sync) - - offset_nas <- which(pl$OFFSET == 0) - pl$OFFSET[offset_nas] <- NA - pl$SLOPE1[offset_nas] <- NA - pl$SLOPE2[offset_nas] <- NA - - cat("Sync model done \n") - cat("Consider saving the sync model for later use - e.g. save(sync_model, file='path_to_sync_save'). \n") - - return(list(pl=pl, plsd=plsd, report=report, obj_val=obj_val, eps_long=eps_long, inp_synced=inp_sync)) -} - - - - -#' Get object inp for synchronization -#' @param sync_dat List containing data.tables with hydrophone information and detections. See e.g. `?ssu1` for example -#' @param max_epo_diff Sets the upper threshold for differences in TOA of sync tags. Best parameter value depends on burst rate of sync tags and how far apart the internal clocks of the hydros are prior to synchronization. A bit less than half of minimum sync tag burst rate is a good starting choice. -#' @param min_hydros Sets the lower threshold of how many hydrophones need to detect each sync tag ping in order to be included in the sync process. Should be as high as possible while observing that all hydrosphones are contributing. If too low, isolated hydrophones risk falling out completely. Future versions will work towards automising this. -#' @param time_keeper_idx Index of the hydrophone to use as time keeper. Could e.g. be the one with smallest overall clock-drift. -#' @param fixed_hydros_idx Vector of hydro idx's for all hydrophones where the position is assumed to be known with adequate accuracy and precission. Include as many as possible as fixed hydros to reduce overall computation time and reduce overall variability. As a bare minimum two hydros need to be fixed, but we strongly advice to use more than two. -#' @param n_offset_day Specifies the number of hydrophone specific quadratic polynomials to use per day. For PPM based systems, 1 or 2 is often adeqaute. -#' @param n_ss_day Specifies number of speed of sound to estimate per day if no ss data is supplied. It is recommended to use logged water temperature instead. However, estimating SS gives an extra option for sanity-checking the final sync-model. -#' @param ss_data_what Indicates whether to estimate ("est") speed of sound or to use data based on logged water temperature ("data"). -#' @param ss_data data.table containing timestamp and speed of sound for the entire period to by synchronised. Must contain columns 'ts' (POSIXct timestamp) and 'ss' speed of sound in m/s (typical values range 1400 - 1550). -#' @param keep_rate Syncing large data sets can take a really long time. However, there is typically an excess number of sync tag detections -#' and a sub-sample is typically enough for good synchronization. -#' This parameter EITHER specifies a proportion (0-1) of data to keep when sub-sampling -#' OR (if keep_rate > 10) number of pings (approximate) to keep in each hydro X offset_idx combination if enough exists. -#' @param excl_self_detect Logical whether to excluded detections of sync tags on the hydros they are co-located with. Sometimes self detections can introduce excessive residuals in the sync model in which case they should be excluded. -#' @param lin_corr_coeffs Matrix of coefficients used for pre-sync linear correction. dim(lin_corr_coeffs)=(#hydros, 2). -#' @param silent_check Logical whether to get output from checkInpSync(). Default is FALSE -#' @example man/examples/example-yaps_ssu1.R -#' @export -getInpSync <- function(sync_dat, max_epo_diff, min_hydros, time_keeper_idx, fixed_hydros_idx, n_offset_day, n_ss_day, keep_rate=1, excl_self_detect=TRUE, lin_corr_coeffs=NA, ss_data_what="est", ss_data=c(0), silent_check=FALSE){ - if(length(unique(sync_dat$hydros$serial)) != nrow(sync_dat$hydros)){ - print(sync_dat$hydros[, .N, by=serial][N>=2]) - stop("ERROR: At least one hydrophone serial number is used more than once in sync_dat$hydros!\n") - } - - if(keep_rate <=0 | (keep_rate > 1 & keep_rate < 10) | (keep_rate >= 10 & keep_rate %% 1 != 0)){ - stop("ERROR: Invalid keep_rate! Must be either ]0;1] or integer >= 10\n") - } - - sync_dat <- appendDetections(sync_dat) - - if(is.na(lin_corr_coeffs[1])){ - lin_corr_coeffs <- matrix(0, nrow=nrow(sync_dat$hydros), ncol=2, byrow=TRUE) - } - - sync_dat <- applyLinCorCoeffsInpSync(sync_dat, lin_corr_coeffs) - - T0 <- min(sync_dat$detections$epo) - - inp_H_info <- getInpSyncHInfo(sync_dat) - - inp_toa_list_all <- getInpSyncToaList(sync_dat, max_epo_diff, min_hydros, excl_self_detect) - fixed_hydros_vec <- getFixedHydrosVec(sync_dat, fixed_hydros_idx) - offset_vals_all <- getOffsetVals(inp_toa_list_all, n_offset_day) - inp_toa_list <- getDownsampledToaList(inp_toa_list_all, offset_vals_all, keep_rate) - offset_vals <- getOffsetVals(inp_toa_list, n_offset_day) - ss_vals <- getSsVals(inp_toa_list, n_ss_day) - if(ss_data_what == "data"){ - ss_data_vec <- getSsDataVec(inp_toa_list, ss_data) - } else { - ss_data_vec <- c(0) - } - - dat_tmb_sync <- getDatTmbSync(sync_dat, time_keeper_idx, inp_toa_list, fixed_hydros_vec, offset_vals, ss_vals, inp_H_info, T0, ss_data_what, ss_data_vec) - params_tmb_sync <- getParamsTmbSync(dat_tmb_sync, ss_data_what) - if(ss_data_what == "est"){ - random_tmb_sync <- c("TOP", "OFFSET", "SLOPE1", "SLOPE2", "SS", "TRUE_H") - } else { - random_tmb_sync <- c("TOP", "OFFSET", "SLOPE1", "SLOPE2", "TRUE_H") - } - # inits_tmb_sync <- c(3, rep(-3,dat_tmb_sync$nh)) - inits_tmb_sync <- c(-3) - inp_params <- list(toa=inp_toa_list$toa, T0=T0, Hx0=inp_H_info$Hx0, Hy0=inp_H_info$Hy0, offset_levels=offset_vals$offset_levels, - ss_levels=ss_vals$ss_levels, max_epo_diff=max_epo_diff, hydros=sync_dat$hydros, - lin_corr_coeffs=lin_corr_coeffs, min_hydros=min_hydros, ss_data=ss_data - ) - - inp_sync <- list(dat_tmb_sync=dat_tmb_sync, params_tmb_sync=params_tmb_sync, random_tmb_sync=random_tmb_sync, inits_tmb_sync=inits_tmb_sync, inp_params=inp_params) - inp_sync$inp_params$sync_coverage <- checkInpSync(inp_sync, silent_check) - return(inp_sync) - -} - #' Internal function. Extract speed of sounds for each timestamp used in sync-process from supplied data. #' @inheritParams getInpSync #' @noRd diff --git a/R/syncPlotters.R b/R/syncPlotters.R index c09494a..8a0cf03 100644 --- a/R/syncPlotters.R +++ b/R/syncPlotters.R @@ -2,8 +2,9 @@ #' #' @param sync_model Synchronization model obtained using `getSyncModel()` #' @param by What to facet/group the plot by? Currently supports one of 'overall', 'sync_tag', 'hydro', 'quantiles', 'temporal', 'temporal_hydro', 'temporal_sync_tag' -#' @example man/examples/example-syncModelPlots.R #' @export +#' @return No return value, called to plot graphics. +#' @example man/examples/example-syncModelPlots.R plotSyncModelResids <- function(sync_model, by='overall'){ eps_long <- sync_model$eps_long if(by == 'overall'){ @@ -55,6 +56,7 @@ plotSyncModelResids <- function(sync_model, by='overall'){ #' Plot hydrophone positions. Especially useful if some hydro re-positioned as part of the sync model. #' @param sync_model Synchronization model obtained using `getSyncModel()` #' @export +#' @return No return value, called to plot graphics. #' @example man/examples/example-syncModelPlots.R plotSyncModelHydros <- function(sync_model){ z_synced <- NULL @@ -90,6 +92,7 @@ plotSyncModelHydros <- function(sync_model){ #' @param sync_model Synchronization model obtained using `getSyncModel()` #' @param by What to facet/group the plot by? Currently supports one of 'sync_bin_sync', 'sync_bin_hydro', 'sync_bin_sync_smooth', 'sync_bin_hydro_smooth', 'hydro', 'sync_tag' #' @export +#' @return No return value, called to plot graphics. #' @example man/examples/example-syncModelPlots.R plotSyncModelCheck <- function(sync_model, by=""){ sync_check_dat <- getSyncCheckDat(sync_model) diff --git a/R/tempToSs.R b/R/tempToSs.R index 9f18e1e..d820ab5 100644 --- a/R/tempToSs.R +++ b/R/tempToSs.R @@ -4,6 +4,7 @@ #' @param sal Water slinity in parts per thousand (promille) #' @param depth Depth in meters - default = 5 m - can typically be ignored #' @export +#' @return Vector of estimated speed of sound in water. #' @examples #' water_temp <- rnorm(100, 20, 2) #' ss <- tempToSs(temp=water_temp, sal=0, depth=5) diff --git a/R/testYaps.R b/R/testYaps.R index ab9ef95..e910b3f 100644 --- a/R/testYaps.R +++ b/R/testYaps.R @@ -8,25 +8,22 @@ #' @inheritParams getInp #' @inheritParams runYaps #' @export +#' @return If `return_yaps == TRUE`, the fitted `yaps` object. See `?runYaps` for further info. + #' @examples -#' \dontrun{ -#' # To test basic functionality of yaps using simulated data +#' #' # To test basic functionality of yaps using simulated data #' testYaps() #' # # # Three pingTypes are availabe: -#' # # # fixed burst interval ('sbi'), -#' # # # random burst interval with UNKNOWN burst interval sequence('rbi'), -#' # # # random burst interval with KNOWN burst interval sequence ('pbi') -#' testYaps(pingType='sbi') -#' testYaps(pingType='rbi') -#' testYaps(pingType='pbi') -#' } +#' # # # fixed burst interval (testYaps(pingType='sbi')), +#' # # # random burst interval with UNKNOWN burst interval sequence('testYaps(pingType='rbi')), +#' # # # random burst interval with KNOWN burst interval sequence (testYaps(pingType='pbi')) testYaps <- function(silent=TRUE, pingType='sbi', est_ss=TRUE, opt_fun='nlminb', opt_controls=list(), bounds=list(), return_yaps=FALSE, tmb_smartsearch=TRUE){ set.seed(42) trueTrack <- simTrueTrack(model='crw', n = 2000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') - # pingType <- 'sbi' if(pingType == 'sbi'){ sbi_mean <- 20; sbi_sd <- 1e-3; - rbi_min <- 0; rbi_max <- 0; + rbi_min <- sbi_mean; + rbi_max <- sbi_mean; teleTrack <- simTelemetryTrack(trueTrack, pingType=pingType, sbi_mean=sbi_mean, sbi_sd=sbi_sd) } else { rbi_min = 30 @@ -51,14 +48,11 @@ testYaps <- function(silent=TRUE, pingType='sbi', est_ss=TRUE, opt_fun='nlminb', ss_data <- teleTrack$ss } inp <- getInp(hydros, toa, E_dist="Mixture", n_ss=5, pingType=pingType, sdInits=0, ss_data_what=ss_data_what, ss_data=ss_data, rbi_min=rbi_min, rbi_max=rbi_max, biTable=biTable) - # print(str(inp)) maxIter <- 500 - # suppressWarnings(outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE, x.tol=1E-3)) - outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE, silent=silent, opt_fun=opt_fun, opt_controls, bounds, tmb_smartsearch) - # print(str(outTmb)) - pl <- outTmb$pl + yaps <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE, silent=silent, opt_fun=opt_fun, opt_controls, bounds, tmb_smartsearch) + pl <- yaps$pl yaps_out <- data.table::data.table(X=pl$X + inp$inp_params$Hx0, Y=pl$Y + inp$inp_params$Hy0) - plsd <- outTmb$plsd + plsd <- yaps$plsd plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy), asp=1, lwd=2) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) @@ -66,5 +60,5 @@ testYaps <- function(silent=TRUE, pingType='sbi', est_ss=TRUE, opt_fun='nlminb', if(!silent) {cat("You should now see a plot of a simulted track - if so YAPS core functions are working \n")} - if(return_yaps) {return(outTmb)} + if(return_yaps) {return(yaps)} } diff --git a/README.Rmd b/README.Rmd index 410bd3f..2f74324 100644 --- a/README.Rmd +++ b/README.Rmd @@ -19,9 +19,11 @@ knitr::opts_chunk$set( ``` +[![CRAN Status Badge](https://www.r-pkg.org/badges/version/yaps)](https://cran.r-project.org/package=yaps) [![R-CMD-check](https://github.com/baktoft/yaps/workflows/R-CMD-check/badge.svg)](https://github.com/baktoft/yaps/actions) -[![Codecov test coverage](https://codecov.io/gh/baktoft/yaps/branch/master/graph/badge.svg)](https://codecov.io/gh/baktoft/yaps?branch=master) [![Travis build status](https://travis-ci.org/baktoft/yaps.svg?branch=master)](https://travis-ci.org/baktoft/yaps) +[![Codecov test coverage](https://codecov.io/gh/baktoft/yaps/branch/master/graph/badge.svg)](https://codecov.io/gh/baktoft/yaps?branch=master) +[![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/grand-total/yaps)](https://cran.r-project.org/package=yaps) diff --git a/README.md b/README.md index 5254254..c094508 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,15 @@ +[![CRAN Status +Badge](https://www.r-pkg.org/badges/version/yaps)](https://cran.r-project.org/package=yaps) [![R-CMD-check](https://github.com/baktoft/yaps/workflows/R-CMD-check/badge.svg)](https://github.com/baktoft/yaps/actions) -[![Codecov test -coverage](https://codecov.io/gh/baktoft/yaps/branch/master/graph/badge.svg)](https://codecov.io/gh/baktoft/yaps?branch=master) [![Travis build status](https://travis-ci.org/baktoft/yaps.svg?branch=master)](https://travis-ci.org/baktoft/yaps) - +[![Codecov test +coverage](https://codecov.io/gh/baktoft/yaps/branch/master/graph/badge.svg)](https://codecov.io/gh/baktoft/yaps?branch=master) +[![CRAN RStudio mirror +downloads](https://cranlogs.r-pkg.org/badges/grand-total/yaps)](https://cran.r-project.org/package=yaps) # YAPS - (Yet Another Positioning Solver) diff --git a/cran-comments.md b/cran-comments.md deleted file mode 100644 index 1b0aa68..0000000 --- a/cran-comments.md +++ /dev/null @@ -1,42 +0,0 @@ -## Comments - -* This is first submission of this package to CRAN. - -* The package contains compiled c++ code, hence it is not possible to bring down the installed package size. - -* win-builder mentions possibly mis-spelled words in DESCRIPTION. These are all author names. - -## Test environments -* Local Windows 10, R 4.0.3, R 4.1.0 (2021-01-20 r79850) -* Ubuntu 16.04 (travis), R 4.0.2 -* Ubuntu 20.04 (github action), R release, R devel -* Windows-latest (github action), R 3.6, R release, R devel -* macOS-latest (github action), R 3.6, R release -* win-builder (oldrelease, release, devel) - -## R CMD check results - -0 errors | 0 warnings | 2 notes - -checking CRAN incoming feasibility ... NOTE -Maintainer: 'Henrik Baktoft ' -New submission - -checking installed package size ... NOTE -installed size is 21.6Mb -sub-directories of 1Mb or more: -libs 19.6Mb - ---- - -On win-builder (oldrelease, release, devel): - -Possibly mis-spelled words in DESCRIPTION: - Baktoft (9:579, 9:729) - Corujo (9:774) - Gjelland (9:588, 9:738) - Rehage (9:756) - Rodemann (9:764) - Thygesen (9:607, 9:792) - Viadero (9:782) - Økland (9:598, 9:748) diff --git a/man/alignBurstSeq.Rd b/man/alignBurstSeq.Rd index 0a812a8..ef9dfd6 100644 --- a/man/alignBurstSeq.Rd +++ b/man/alignBurstSeq.Rd @@ -22,16 +22,17 @@ alignBurstSeq( \item{rbi_min, rbi_max}{Minimum and maximum burst interval of the transmitter. Used to identify sequence of consecutive pings in the data} -\item{plot_diag}{Logical indicating if visual diagnosis plots should be created. -return data.table like input, but with extra columns seq_ping_idx and seq_epo} +\item{plot_diag}{Logical indicating if visual diagnosis plots should be created.} +} +\value{ +\code{data.table} like the input \code{synced_dat}, but with extra columns seq_ping_idx and seq_epo } \description{ -Identifies where in the sequence of known burst intervals the detected data is from. +Identifies where in the sequence of known burst intervals the detected data is from. Add extra columns to data.table containing ping index of the burst sequence (seq_ping_idx) and expected time of ping (seq_epo). Only to be used for 'random' burst interval data when you know the burst sequence. } \examples{ -\dontrun{ # Align data from a tag with known random burst interval to the burst interval sequence # using the hald data included in `yapsdata` (see ?yapsdata::hald for info). synced_dat_1315 <- dat_align$synced_dat_1315 @@ -40,6 +41,4 @@ rbi_min <- 60 rbi_max <- 120 aligned_dat <- alignBurstSeq(synced_dat=synced_dat_1315, burst_seq=seq_1315, rbi_min=rbi_min, rbi_max=rbi_max, plot_diag=TRUE) - -} } diff --git a/man/applySync.Rd b/man/applySync.Rd index 32c3698..3142574 100644 --- a/man/applySync.Rd +++ b/man/applySync.Rd @@ -7,17 +7,20 @@ applySync(toa, hydros = "", sync_model) } \arguments{ -\item{toa}{Object containing data to be synchronized. Typically a `data.table` as e.g. `ssu1$detections`, but can also be a matrix dim=(n_ping, n_hydo).} +\item{toa}{Object containing data to be synchronized. Typically a \code{data.table} as e.g. \code{ssu1$detections}, but can also be a matrix dim=(n_ping, n_hydo).} -\item{hydros}{data.table formatted as `ssu1$hydros`} +\item{hydros}{data.table formatted as \code{ssu1$hydros}} -\item{sync_model}{Synchronization model obtained using `getSyncModel()`} +\item{sync_model}{Synchronization model obtained using \code{getSyncModel()}} +} +\value{ +A \code{data.table} with the now synchronized time-of-arrivals in column \code{eposync}. } \description{ Apply sync model to toa matrix to obtain synced data } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -45,8 +48,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -56,11 +58,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -72,7 +74,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -83,6 +86,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -102,6 +107,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/checkInp.Rd b/man/checkInp.Rd index 2af1a30..1cb1151 100644 --- a/man/checkInp.Rd +++ b/man/checkInp.Rd @@ -2,18 +2,21 @@ % Please edit documentation in R/checkInp.R \name{checkInp} \alias{checkInp} -\title{Check consistency of `inp` object obtained from `getInp()`} +\title{Check consistency of \code{inp} object obtained from \code{getInp()}} \usage{ checkInp(inp) } \arguments{ -\item{inp}{Object obtained using `getInp()`} +\item{inp}{Object obtained using \code{getInp()}} +} +\value{ +No return value, but prints errors/warnings if issues with \code{inp} is detected. } \description{ -Check consistency of `inp` object obtained from `getInp()` +Check consistency of \code{inp} object obtained from \code{getInp()} } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -41,8 +44,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -52,11 +54,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -68,7 +70,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -79,6 +82,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -98,6 +103,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/checkInpSync.Rd b/man/checkInpSync.Rd index fbbc5bd..e9b74d4 100644 --- a/man/checkInpSync.Rd +++ b/man/checkInpSync.Rd @@ -2,20 +2,23 @@ % Please edit documentation in R/checkInpSync.R \name{checkInpSync} \alias{checkInpSync} -\title{Check consistency of `inp_sync` object obtained from `getInpSync()`} +\title{Check consistency of \code{inp_sync} object obtained from \code{getInpSync()}} \usage{ checkInpSync(inp_sync, silent_check) } \arguments{ -\item{inp_sync}{Object obtained using `getInpSync()`} +\item{inp_sync}{Object obtained using \code{getInpSync()}} -\item{silent_check}{Logical whether to get output from checkInpSync(). Default is FALSE} +\item{silent_check}{Logical whether to get output from \code{checkInpSync()}. Default is FALSE} +} +\value{ +No return value, but prints errors/warnings if issues with \code{inp_sync} is detected. } \description{ -Check consistency of `inp_sync` object obtained from `getInpSync()` +Check consistency of \code{inp_sync} object obtained from \code{getInpSync()} } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -43,8 +46,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -54,11 +56,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -70,7 +72,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -81,6 +84,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -100,6 +105,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/dat_align.Rd b/man/dat_align.Rd index 9508166..f4a616c 100644 --- a/man/dat_align.Rd +++ b/man/dat_align.Rd @@ -7,12 +7,12 @@ \format{ A list containing 2 items: \describe{ - \item{synced_dat_1315}{ - data.table containing synced detections of tag 1315. - } - \item{synced_dat_1315}{ - vector of small part of the complete sequence of known random BIs. - } +\item{synced_dat_1315}{ +data.table containing synced detections of tag 1315. +} +\item{synced_dat_1315}{ +vector of small part of the complete sequence of known random BIs. +} } } \usage{ @@ -21,6 +21,6 @@ dat_align \description{ Function alignBurstSeq() is used to align synced detection data with a sequence of known random burst intervals (BI). \cr This step is needed to take advantage of the extra information available when working with random BI data with a known sequence. \cr -This small sample is obtained from the accompanying data package `yapsdata`. +This small sample is obtained from the accompanying data package \code{yapsdata}. } \keyword{datasets} diff --git a/man/examples/example-alignBurstSeq.R b/man/examples/example-alignBurstSeq.R index b1e94bf..4eda6c8 100644 --- a/man/examples/example-alignBurstSeq.R +++ b/man/examples/example-alignBurstSeq.R @@ -1,4 +1,3 @@ -\dontrun{ # Align data from a tag with known random burst interval to the burst interval sequence # using the hald data included in `yapsdata` (see ?yapsdata::hald for info). synced_dat_1315 <- dat_align$synced_dat_1315 @@ -7,5 +6,3 @@ rbi_min <- 60 rbi_max <- 120 aligned_dat <- alignBurstSeq(synced_dat=synced_dat_1315, burst_seq=seq_1315, rbi_min=rbi_min, rbi_max=rbi_max, plot_diag=TRUE) - -} \ No newline at end of file diff --git a/man/examples/example-bbox.R b/man/examples/example-bbox.R index cb81f58..1bfefcc 100644 --- a/man/examples/example-bbox.R +++ b/man/examples/example-bbox.R @@ -1,6 +1,4 @@ -\dontrun{ hydros <- ssu1$hydros colnames(hydros) <- c('serial','hx','hy','hz','sync_tag','idx') bbox <- getBbox(hydros) plotBbox(hydros, bbox) -} \ No newline at end of file diff --git a/man/examples/example-syncModelPlots.R b/man/examples/example-syncModelPlots.R index fb8f79f..f5a3a20 100644 --- a/man/examples/example-syncModelPlots.R +++ b/man/examples/example-syncModelPlots.R @@ -1,4 +1,4 @@ -\dontrun{ +\donttest{ sync_model <- ssu1$sync_model plotSyncModelHydros(sync_model) @@ -15,8 +15,4 @@ plotSyncModelCheck(sync_model, by = "hydro") plotSyncModelCheck(sync_model, by = "sync_tag") plotSyncModelCheck(sync_model, by = "sync_bin_sync") plotSyncModelCheck(sync_model, by = "sync_bin_hydro") -# # # if more sync periods are used, these two can be applied -# plotSyncModelCheck(sync_model, by = "sync_bin_sync_smooth") -# plotSyncModelCheck(sync_model, by = "sync_bin_hydro_smooth") - -} \ No newline at end of file +} diff --git a/man/examples/example-yaps_sim.R b/man/examples/example-yaps_sim.R index 2e4c505..6417631 100644 --- a/man/examples/example-yaps_sim.R +++ b/man/examples/example-yaps_sim.R @@ -1,8 +1,8 @@ -\dontrun{ +\donttest{ library(yaps) set.seed(42) # Simulate true track of animal movement of n seconds -trueTrack <- simTrueTrack(model='crw', n = 3000, deltaTime=1, shape=1, +trueTrack <- simTrueTrack(model='crw', n = 1000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') # Simulate telemetry observations from true track. @@ -38,7 +38,7 @@ if(pingType == 'sbi'){ pl <- c() maxIter <- ifelse(pingType=="sbi", 500, 5000) -outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) +outTmb <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) # Estimates in pl pl <- outTmb$pl @@ -55,5 +55,4 @@ plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) lines(pl$Y~pl$X, col="red") - } \ No newline at end of file diff --git a/man/examples/example-yaps_ssu1.R b/man/examples/example-yaps_ssu1.R index 5e50bf1..7a42e5d 100644 --- a/man/examples/example-yaps_ssu1.R +++ b/man/examples/example-yaps_ssu1.R @@ -1,4 +1,4 @@ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -26,8 +26,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -37,11 +36,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -53,7 +52,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -64,6 +64,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -83,5 +85,5 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } \ No newline at end of file diff --git a/man/fineTuneSyncModel.Rd b/man/fineTuneSyncModel.Rd index b7870c1..e898ab8 100644 --- a/man/fineTuneSyncModel.Rd +++ b/man/fineTuneSyncModel.Rd @@ -14,12 +14,15 @@ fineTuneSyncModel(sync_model, eps_threshold, silent = TRUE) \item{silent}{logical whether to make getSyncModel() silent} } +\value{ +Fine tuned \code{sync_model}. See \code{?getSyncModel} for more info. +} \description{ Fine-tune an already fitted sync_model Wrapper function to re-run getSyncModel() using the same data, but excluding outliers. Note dimensions of data might change if eps_threshold results in empty rows in the TOA-matrix. } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -47,8 +50,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -58,11 +60,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -74,7 +76,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -85,93 +88,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps -par(mfrow=c(2,2)) -plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") -lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) -lines(y~x, data=yaps_out$track, col="red") - -plot(utm_x~ts, data=ssu1$gps, col="blue", type="l", lwd=2) -points(x~top, data=yaps_out$track, col="red") -lines(x~top, data=yaps_out$track, col="red") -lines(x-2*x_sd~top, data=yaps_out$track, col="red", lty=2) -lines(x+2*x_sd~top, data=yaps_out$track, col="red", lty=2) - -plot(utm_y~ts, data=ssu1$gps, col="blue", type="l", lwd=2) -points(y~top, data=yaps_out$track, col="red") -lines(y~top, data=yaps_out$track, col="red") -lines(y-2*y_sd~top, data=yaps_out$track, col="red", lty=2) -lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) - -plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") -lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) -} -\dontrun{ -library(yaps) -set.seed(42) - -# # # Example using the ssu1 data included in package. See ?ssu1 for info. -# # # Set parameters to use in the sync model - these will differ per study -max_epo_diff <- 120 -min_hydros <- 2 -time_keeper_idx <- 5 -fixed_hydros_idx <- c(2:3, 6, 8, 11, 13:17) -n_offset_day <- 2 -n_ss_day <- 2 -keep_rate <- 15 - -# # # Get input data ready for getSyncModel() -inp_sync <- getInpSync(sync_dat=ssu1, max_epo_diff, min_hydros, time_keeper_idx, - fixed_hydros_idx, n_offset_day, n_ss_day, keep_rate=keep_rate, silent_check=TRUE) - -# # # Check that inp_sync is ok -checkInpSync(inp_sync, silent_check=FALSE) - -# # # Also take a look at coverage of the sync data -getSyncCoverage(inp_sync, plot=TRUE) - -# # # Fit the sync model -sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) - -# # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) - -# # # Visualize the resulting sync model -plotSyncModelResids(sync_model, by = "overall") -plotSyncModelResids(sync_model, by = "quantiles") -plotSyncModelResids(sync_model, by = "sync_tag") -plotSyncModelResids(sync_model, by = "hydro") -plotSyncModelResids(sync_model, by = "temporal_hydro") -plotSyncModelResids(sync_model, by = "temporal_sync_tag") - -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) - -# # # Apply the sync_model to detections data. -detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) - -# # # Prepare data for running yaps -hydros_yaps <- data.table::data.table(sync_model$pl$TRUE_H) -colnames(hydros_yaps) <- c('hx','hy','hz') -focal_tag <- 15266 -rbi_min <- 20 -rbi_max <- 40 -synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) -inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", - sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) - -# # # Check that inp is ok -checkInp(inp) - -# # # Run yaps on the prepared data to estimate track -yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) - -# # # Plot the results and compare to "the truth" obtained using gps +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -191,6 +109,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/getBbox.Rd b/man/getBbox.Rd index eb3a1a7..549d556 100644 --- a/man/getBbox.Rd +++ b/man/getBbox.Rd @@ -15,15 +15,15 @@ getBbox(hydros, buffer = 5, eps = 0.001, pen = 1) \item{pen}{Specifies the penalty multiplier.} } +\value{ +Vector of lenght 6: c(x_min, x_max, y_min, y_max, eps, pen). Limits are given in UTM coordinates. +} \description{ Standard is a rectangle based on coordinates of outer hydros +- the buffer in meters -Returns a vector of lenght 6: c(x_min, x_max, y_min, y_max, eps, pen). Limits are given in UTM coordinates. } \examples{ -\dontrun{ hydros <- ssu1$hydros colnames(hydros) <- c('serial','hx','hy','hz','sync_tag','idx') bbox <- getBbox(hydros) plotBbox(hydros, bbox) } -} diff --git a/man/getInp.Rd b/man/getInp.Rd index 417c979..987f207 100644 --- a/man/getInp.Rd +++ b/man/getInp.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/prepTmb.R +% Please edit documentation in R/getInp.R \name{getInp} \alias{getInp} \title{Get prepared inp-object for use in TMB-call} @@ -46,8 +46,99 @@ getInp( \item{bbox}{Spatial constraints in the form of a bounding box. See ?getBbox for details.} } \value{ -List of input data ready for use in TMB-call +List of input data ready for use in \code{runYaps()} } \description{ Wrapper-function to compile a list of input needed to run TMB } +\examples{ +\donttest{ +library(yaps) +set.seed(42) + +# # # Example using the ssu1 data included in package. See ?ssu1 for info. +# # # Set parameters to use in the sync model - these will differ per study +max_epo_diff <- 120 +min_hydros <- 2 +time_keeper_idx <- 5 +fixed_hydros_idx <- c(2:3, 6, 8, 11, 13:17) +n_offset_day <- 2 +n_ss_day <- 2 +keep_rate <- 15 + +# # # Get input data ready for getSyncModel() +inp_sync <- getInpSync(sync_dat=ssu1, max_epo_diff, min_hydros, time_keeper_idx, + fixed_hydros_idx, n_offset_day, n_ss_day, keep_rate=keep_rate, silent_check=TRUE) + +# # # Check that inp_sync is ok +checkInpSync(inp_sync, silent_check=FALSE) + +# # # Also take a look at coverage of the sync data +getSyncCoverage(inp_sync, plot=TRUE) + +# # # Fit the sync model +sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) + +# # # On some systems it might work better, if we disbale the smartsearch feature in TMB +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() + +# # # Visualize the resulting sync model +plotSyncModelResids(sync_model, by = "overall") +plotSyncModelResids(sync_model, by = "quantiles") +plotSyncModelResids(sync_model, by = "sync_tag") +plotSyncModelResids(sync_model, by = "hydro") +plotSyncModelResids(sync_model, by = "temporal_hydro") +plotSyncModelResids(sync_model, by = "temporal_sync_tag") + +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) + +# # # Apply the sync_model to detections data. +detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) + +# # # Prepare data for running yaps +hydros_yaps <- data.table::data.table(sync_model$pl$TRUE_H) +colnames(hydros_yaps) <- c('hx','hy','hz') +focal_tag <- 15266 +rbi_min <- 20 +rbi_max <- 40 +synced_dat <- detections_synced[tag == focal_tag] +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) +inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", + sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) + +# # # Check that inp is ok +checkInp(inp) + +# # # Run yaps on the prepared data to estimate track +yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) + +# # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) +par(mfrow=c(2,2)) +plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") +lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) +lines(y~x, data=yaps_out$track, col="red") + +plot(utm_x~ts, data=ssu1$gps, col="blue", type="l", lwd=2) +points(x~top, data=yaps_out$track, col="red") +lines(x~top, data=yaps_out$track, col="red") +lines(x-2*x_sd~top, data=yaps_out$track, col="red", lty=2) +lines(x+2*x_sd~top, data=yaps_out$track, col="red", lty=2) + +plot(utm_y~ts, data=ssu1$gps, col="blue", type="l", lwd=2) +points(y~top, data=yaps_out$track, col="red") +lines(y~top, data=yaps_out$track, col="red") +lines(y-2*y_sd~top, data=yaps_out$track, col="red", lty=2) +lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) + +plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") +lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) +par(oldpar) +} +} diff --git a/man/getInpSync.Rd b/man/getInpSync.Rd index a7a56a6..80a01fb 100644 --- a/man/getInpSync.Rd +++ b/man/getInpSync.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/syncGetters.R +% Please edit documentation in R/getInpSync.R \name{getInpSync} \alias{getInpSync} \title{Get object inp for synchronization} @@ -21,7 +21,7 @@ getInpSync( ) } \arguments{ -\item{sync_dat}{List containing data.tables with hydrophone information and detections. See e.g. `?ssu1` for example} +\item{sync_dat}{List containing data.tables with hydrophone information and detections. See e.g. \code{?ssu1} for example} \item{max_epo_diff}{Sets the upper threshold for differences in TOA of sync tags. Best parameter value depends on burst rate of sync tags and how far apart the internal clocks of the hydros are prior to synchronization. A bit less than half of minimum sync tag burst rate is a good starting choice.} @@ -35,26 +35,29 @@ getInpSync( \item{n_ss_day}{Specifies number of speed of sound to estimate per day if no ss data is supplied. It is recommended to use logged water temperature instead. However, estimating SS gives an extra option for sanity-checking the final sync-model.} -\item{keep_rate}{Syncing large data sets can take a really long time. However, there is typically an excess number of sync tag detections -and a sub-sample is typically enough for good synchronization. -This parameter EITHER specifies a proportion (0-1) of data to keep when sub-sampling +\item{keep_rate}{Syncing large data sets can take a really long time. However, there is typically an excess number of sync tag detections +and a sub-sample is typically enough for good synchronization. +This parameter EITHER specifies a proportion (0-1) of data to keep when sub-sampling OR (if keep_rate > 10) number of pings (approximate) to keep in each hydro X offset_idx combination if enough exists.} \item{excl_self_detect}{Logical whether to excluded detections of sync tags on the hydros they are co-located with. Sometimes self detections can introduce excessive residuals in the sync model in which case they should be excluded.} -\item{lin_corr_coeffs}{Matrix of coefficients used for pre-sync linear correction. dim(lin_corr_coeffs)=(#hydros, 2).} +\item{lin_corr_coeffs}{Matrix of coefficients used for pre-sync linear correction. \verb{dim(lin_corr_coeffs)=(#hydros, 2)}.} \item{ss_data_what}{Indicates whether to estimate ("est") speed of sound or to use data based on logged water temperature ("data").} \item{ss_data}{data.table containing timestamp and speed of sound for the entire period to by synchronised. Must contain columns 'ts' (POSIXct timestamp) and 'ss' speed of sound in m/s (typical values range 1400 - 1550).} -\item{silent_check}{Logical whether to get output from checkInpSync(). Default is FALSE} +\item{silent_check}{Logical whether to get output from \code{checkInpSync()}. Default is FALSE} +} +\value{ +List of input data ready for use in \code{getSyncModel()} } \description{ Get object inp for synchronization } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -82,8 +85,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -93,11 +95,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -109,7 +111,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -120,6 +123,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -139,6 +144,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/getSyncCoverage.Rd b/man/getSyncCoverage.Rd index 906604e..908a487 100644 --- a/man/getSyncCoverage.Rd +++ b/man/getSyncCoverage.Rd @@ -7,10 +7,104 @@ getSyncCoverage(inp_sync, plot = FALSE) } \arguments{ -\item{inp_sync}{Object obtained using `getInpSync()`} +\item{inp_sync}{Object obtained using \code{getInpSync()}} \item{plot}{Logical indicating whether to plot a visual or not.} } +\value{ +A data.table containing number of pings included in each hydro x offset combination. +} \description{ Quick overview to check if all hydros have enough data within each offset period. } +\examples{ +\donttest{ +library(yaps) +set.seed(42) + +# # # Example using the ssu1 data included in package. See ?ssu1 for info. +# # # Set parameters to use in the sync model - these will differ per study +max_epo_diff <- 120 +min_hydros <- 2 +time_keeper_idx <- 5 +fixed_hydros_idx <- c(2:3, 6, 8, 11, 13:17) +n_offset_day <- 2 +n_ss_day <- 2 +keep_rate <- 15 + +# # # Get input data ready for getSyncModel() +inp_sync <- getInpSync(sync_dat=ssu1, max_epo_diff, min_hydros, time_keeper_idx, + fixed_hydros_idx, n_offset_day, n_ss_day, keep_rate=keep_rate, silent_check=TRUE) + +# # # Check that inp_sync is ok +checkInpSync(inp_sync, silent_check=FALSE) + +# # # Also take a look at coverage of the sync data +getSyncCoverage(inp_sync, plot=TRUE) + +# # # Fit the sync model +sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) + +# # # On some systems it might work better, if we disbale the smartsearch feature in TMB +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() + +# # # Visualize the resulting sync model +plotSyncModelResids(sync_model, by = "overall") +plotSyncModelResids(sync_model, by = "quantiles") +plotSyncModelResids(sync_model, by = "sync_tag") +plotSyncModelResids(sync_model, by = "hydro") +plotSyncModelResids(sync_model, by = "temporal_hydro") +plotSyncModelResids(sync_model, by = "temporal_sync_tag") + +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) + +# # # Apply the sync_model to detections data. +detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) + +# # # Prepare data for running yaps +hydros_yaps <- data.table::data.table(sync_model$pl$TRUE_H) +colnames(hydros_yaps) <- c('hx','hy','hz') +focal_tag <- 15266 +rbi_min <- 20 +rbi_max <- 40 +synced_dat <- detections_synced[tag == focal_tag] +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) +inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", + sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) + +# # # Check that inp is ok +checkInp(inp) + +# # # Run yaps on the prepared data to estimate track +yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) + +# # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) +par(mfrow=c(2,2)) +plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") +lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) +lines(y~x, data=yaps_out$track, col="red") + +plot(utm_x~ts, data=ssu1$gps, col="blue", type="l", lwd=2) +points(x~top, data=yaps_out$track, col="red") +lines(x~top, data=yaps_out$track, col="red") +lines(x-2*x_sd~top, data=yaps_out$track, col="red", lty=2) +lines(x+2*x_sd~top, data=yaps_out$track, col="red", lty=2) + +plot(utm_y~ts, data=ssu1$gps, col="blue", type="l", lwd=2) +points(y~top, data=yaps_out$track, col="red") +lines(y~top, data=yaps_out$track, col="red") +lines(y-2*y_sd~top, data=yaps_out$track, col="red", lty=2) +lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) + +plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") +lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) +par(oldpar) +} +} diff --git a/man/getSyncModel.Rd b/man/getSyncModel.Rd index bc3eade..08c4c71 100644 --- a/man/getSyncModel.Rd +++ b/man/getSyncModel.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/syncGetters.R +% Please edit documentation in R/getSyncModel.R \name{getSyncModel} \alias{getSyncModel} -\title{Get sync model from inp_sync object obtained by getInpSync()} +\title{Get sync model from inp_sync object obtained by \code{getInpSync()}} \usage{ getSyncModel( inp_sync, @@ -13,21 +13,24 @@ getSyncModel( ) } \arguments{ -\item{inp_sync}{Input data prepared for the sync model using `getInpSync()`} +\item{inp_sync}{Input data prepared for the sync model using \code{getInpSync()}} \item{silent}{Keep TMB quiet} -\item{fine_tune}{Logical. Whether to re-run the sync model excluding residual outliers. Consider to use fineTuneSyncModel() instead.} +\item{fine_tune}{Logical. Whether to re-run the sync model excluding residual outliers. \strong{Deprecated} use fineTuneSyncModel() instead.} \item{max_iter}{Max number of iterations to run TMB. Default=100 seems to work in most cases.} -\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see ?TMB::MakeADFun for info). Default and original implementation is TRUE. However, there seems to be an issue with Matrix v1.3.2 that requires tmb_smartsearch=FALSE.} +\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see \code{?TMB::MakeADFun} for info). Default and original implementation is TRUE. However, there seems to be an issue with some versions of \code{Matrix} that requires \code{tmb_smartsearch=FALSE}.} +} +\value{ +List containing relevant data constituting the \code{sync_model} ready for use in \code{fineTuneSyncModel()} if needed or in \code{applySync()} } \description{ -Get sync model from inp_sync object obtained by getInpSync() +Get sync model from inp_sync object obtained by \code{getInpSync()} } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -55,8 +58,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -66,11 +68,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -82,7 +84,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -93,6 +96,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -112,6 +117,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/getToaYaps.Rd b/man/getToaYaps.Rd index e50e306..b8a6d6f 100644 --- a/man/getToaYaps.Rd +++ b/man/getToaYaps.Rd @@ -4,22 +4,27 @@ \alias{getToaYaps} \title{Build TOA matrix from synced data.table - also do some pre-filtering of severe MP, pruning loose ends etc} \usage{ -getToaYaps(synced_dat, hydros, rbi_min, rbi_max) +getToaYaps(synced_dat, hydros, rbi_min, rbi_max, pingType = NULL) } \arguments{ -\item{synced_dat}{`data.table` containing synchronized data formatted as output from/or obtained using `applySync()`} +\item{synced_dat}{\code{data.table} containing synchronized data formatted as output from/or obtained using \code{applySync()}} \item{hydros}{Dataframe from simHydros() or Dataframe with columns hx and hy containing positions of the receivers. Translate the coordinates to get the grid centre close to (0;0).} \item{rbi_min}{Minimum and maximum BI for random burst interval transmitters} \item{rbi_max}{Minimum and maximum BI for random burst interval transmitters} + +\item{pingType}{Type of transmitter to simulate - either stable burst interval ('sbi'), random burst interval ('rbi') or random burst interval but where the random sequence is known a priori} +} +\value{ +Matrix of time-of-arrivals. One coloumn per hydro, one row per ping. } \description{ Build TOA matrix from synced data.table - also do some pre-filtering of severe MP, pruning loose ends etc } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -47,8 +52,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -58,11 +62,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -74,7 +78,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -85,6 +90,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -104,6 +111,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/plotBbox.Rd b/man/plotBbox.Rd index 71c3f98..bdb01b5 100644 --- a/man/plotBbox.Rd +++ b/man/plotBbox.Rd @@ -11,14 +11,15 @@ plotBbox(hydros, bbox) \item{bbox}{Spatial constraints in the form of a bounding box. See ?getBbox for details.} } +\value{ +No return value, called to plot graphic. +} \description{ Graphical representation of spatial constraints } \examples{ -\dontrun{ hydros <- ssu1$hydros colnames(hydros) <- c('serial','hx','hy','hz','sync_tag','idx') bbox <- getBbox(hydros) plotBbox(hydros, bbox) } -} diff --git a/man/plotSyncModelCheck.Rd b/man/plotSyncModelCheck.Rd index 6ad776d..3e10c52 100644 --- a/man/plotSyncModelCheck.Rd +++ b/man/plotSyncModelCheck.Rd @@ -7,17 +7,20 @@ plotSyncModelCheck(sync_model, by = "") } \arguments{ -\item{sync_model}{Synchronization model obtained using `getSyncModel()`} +\item{sync_model}{Synchronization model obtained using \code{getSyncModel()}} \item{by}{What to facet/group the plot by? Currently supports one of 'sync_bin_sync', 'sync_bin_hydro', 'sync_bin_sync_smooth', 'sync_bin_hydro_smooth', 'hydro', 'sync_tag'} } +\value{ +No return value, called to plot graphics. +} \description{ -Delta values indicate absolute difference between true and estimated distances based on pairwise relative distances to sync_tag. +Delta values indicate absolute difference between true and estimated distances based on pairwise relative distances to sync_tag. For instance, a ping from sync_tag t colocated with hydro Ht is detected by hydros H1 and H2. The pairwise relative distance to sync tag is then delta = abs((true_dist(Ht, H1) - true_dist(Ht, H2)) - (est_dist(Ht, H1) - est_dist(Ht, H2))) } \examples{ -\dontrun{ +\donttest{ sync_model <- ssu1$sync_model plotSyncModelHydros(sync_model) @@ -34,9 +37,5 @@ plotSyncModelCheck(sync_model, by = "hydro") plotSyncModelCheck(sync_model, by = "sync_tag") plotSyncModelCheck(sync_model, by = "sync_bin_sync") plotSyncModelCheck(sync_model, by = "sync_bin_hydro") -# # # if more sync periods are used, these two can be applied -# plotSyncModelCheck(sync_model, by = "sync_bin_sync_smooth") -# plotSyncModelCheck(sync_model, by = "sync_bin_hydro_smooth") - } } diff --git a/man/plotSyncModelHydros.Rd b/man/plotSyncModelHydros.Rd index 6e8f4b0..ac82a54 100644 --- a/man/plotSyncModelHydros.Rd +++ b/man/plotSyncModelHydros.Rd @@ -7,13 +7,16 @@ plotSyncModelHydros(sync_model) } \arguments{ -\item{sync_model}{Synchronization model obtained using `getSyncModel()`} +\item{sync_model}{Synchronization model obtained using \code{getSyncModel()}} +} +\value{ +No return value, called to plot graphics. } \description{ Plot hydrophone positions. Especially useful if some hydro re-positioned as part of the sync model. } \examples{ -\dontrun{ +\donttest{ sync_model <- ssu1$sync_model plotSyncModelHydros(sync_model) @@ -30,9 +33,5 @@ plotSyncModelCheck(sync_model, by = "hydro") plotSyncModelCheck(sync_model, by = "sync_tag") plotSyncModelCheck(sync_model, by = "sync_bin_sync") plotSyncModelCheck(sync_model, by = "sync_bin_hydro") -# # # if more sync periods are used, these two can be applied -# plotSyncModelCheck(sync_model, by = "sync_bin_sync_smooth") -# plotSyncModelCheck(sync_model, by = "sync_bin_hydro_smooth") - } } diff --git a/man/plotSyncModelResids.Rd b/man/plotSyncModelResids.Rd index a7ede98..17f325c 100644 --- a/man/plotSyncModelResids.Rd +++ b/man/plotSyncModelResids.Rd @@ -7,15 +7,18 @@ plotSyncModelResids(sync_model, by = "overall") } \arguments{ -\item{sync_model}{Synchronization model obtained using `getSyncModel()`} +\item{sync_model}{Synchronization model obtained using \code{getSyncModel()}} \item{by}{What to facet/group the plot by? Currently supports one of 'overall', 'sync_tag', 'hydro', 'quantiles', 'temporal', 'temporal_hydro', 'temporal_sync_tag'} } +\value{ +No return value, called to plot graphics. +} \description{ Plot residuals of sync_model to enable check of model } \examples{ -\dontrun{ +\donttest{ sync_model <- ssu1$sync_model plotSyncModelHydros(sync_model) @@ -32,9 +35,5 @@ plotSyncModelCheck(sync_model, by = "hydro") plotSyncModelCheck(sync_model, by = "sync_tag") plotSyncModelCheck(sync_model, by = "sync_bin_sync") plotSyncModelCheck(sync_model, by = "sync_bin_hydro") -# # # if more sync periods are used, these two can be applied -# plotSyncModelCheck(sync_model, by = "sync_bin_sync_smooth") -# plotSyncModelCheck(sync_model, by = "sync_bin_hydro_smooth") - } } diff --git a/man/plotYaps.Rd b/man/plotYaps.Rd index d9e7c54..36382aa 100644 --- a/man/plotYaps.Rd +++ b/man/plotYaps.Rd @@ -15,6 +15,9 @@ plotYaps(yaps_out, type = "map", xlim = NULL, ylim = NULL, main = NULL) \item{main}{Title of plot - optional.} } +\value{ +No return value, called to plot graphics. +} \description{ Basic plots of yaps output } diff --git a/man/prepDetections.Rd b/man/prepDetections.Rd index b4b8cd4..6f5ecfa 100644 --- a/man/prepDetections.Rd +++ b/man/prepDetections.Rd @@ -11,11 +11,14 @@ prepDetections(raw_dat, type) \item{type}{Type of the vendor file. Currently only 'vemco_vue' is supported.} } +\value{ +\code{data.table} containing detections extracted from manufacturer data file. +} \description{ Experimental! Prepare detections data.table from raw data - csv-files exported from vendor software } \examples{ \dontrun{ -prepped_detections <- prepDetection("path-to-raw-data-file", type="vemco_vue") +prepped_detections <- prepDetections("path-to-raw-data-file", type="vemco_vue") } } diff --git a/man/runYaps.Rd b/man/runYaps.Rd index 7a56089..6d40a01 100644 --- a/man/runYaps.Rd +++ b/man/runYaps.Rd @@ -30,27 +30,43 @@ runTmb( ) } \arguments{ -\item{inp}{inp-object obtained from getInp()} +\item{inp}{inp-object obtained from \code{getInp()}} -\item{maxIter}{Sets inner.control(maxit) of the tmb-call. Increase if model is not converging.} +\item{maxIter}{Sets \code{inner.control(maxit)} of the TMB-call. Increase if model is not converging.} \item{getPlsd, getRep}{Whether or not to get sd estimates (plsd=TRUE) and reported values (getRep=TRUE).} \item{silent}{Logical whether to keep the optimization quiet.} -\item{opt_fun}{Which optimization function to use. Default is 'nlminb' - alternative is 'nloptr' (experimental!). If using 'nloptr', `opt_controls` must be specified.} +\item{opt_fun}{Which optimization function to use. Default is \code{opt_fun = 'nlminb'} - alternative is \code{opt_fun = 'nloptr'} (experimental!). If using nloptr, \code{opt_controls} must be specified.} -\item{opt_controls}{List of controls passed to optimization function. For instances, tolerances such as x.tol=1E-8. If opt_fun = 'nloptr', `opt_controls` must be a list formatted appropriately. For instance: opt_controls <- list(algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) ). See `?nloptr` and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in `nloptr` require bounded parameters - see `bounds`.} +\item{opt_controls}{List of controls passed to optimization function. For instances, tolerances such as \code{x.tol=1E-8}. \cr +If \code{opt_fun = 'nloptr'}, \code{opt_controls} must be a list formatted appropriately. For instance: \cr +\code{opt_controls <- list( algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) )}. \cr +See \code{?nloptr} and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in \code{nloptr} require bounded parameters - see \code{bounds}.} -\item{bounds}{List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) ).} +\item{bounds}{List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, \code{bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) )}.} -\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see ?TMB::MakeADFun for info). Default and original implementation is TRUE. However, there seems to be an issue with Matrix v1.3.2 that requires tmb_smartsearch=FALSE.} +\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see \code{?TMB::MakeADFun} for info). Default and original implementation is TRUE. However, there seems to be an issue with recent versions of \code{Matrix} that requires \code{tmb_smartsearch=FALSE}.} +} +\value{ +List containing results of fitting \code{yaps} to the data. +\describe{ +\item{pl}{List containing all parameter estimates.} +\item{plsd}{List containing standard errors of parameter estimates.} +\item{rep}{List containing \code{mu_toa}.} +\item{obj}{Numeric obj value of the fitted model obtained using \code{obj$fn()}.} +\item{inp}{List containing the \code{inp} object used in \code{runYaps()}. See \code{?getInp} for further info.} +\item{conv_status}{Integer convergence status.} +\item{conv_message}{Text version of convergence status.} +\item{track}{A data.table containing the estimated track including time-of-ping (top), standard errors and number of hydros detecting each ping (nobs).} +} } \description{ Function to run TMB to estimate track } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) @@ -78,8 +94,7 @@ getSyncCoverage(inp_sync, plot=TRUE) sync_model <- getSyncModel(inp_sync, silent=TRUE, max_iter=200, tmb_smartsearch = TRUE) # # # On some systems it might work better, if we disbale the smartsearch feature in TMB -# sync_model_no_smartsearch <- getSyncModel(inp_sync, silent=TRUE, max_iter=5000, - # tmb_smartsearch = FALSE) +# # # To do so, set tmb_smartsearch = FALSE in getSyncModel() # # # Visualize the resulting sync model plotSyncModelResids(sync_model, by = "overall") @@ -89,11 +104,11 @@ plotSyncModelResids(sync_model, by = "hydro") plotSyncModelResids(sync_model, by = "temporal_hydro") plotSyncModelResids(sync_model, by = "temporal_sync_tag") -# # # If the above plots show outlier, sync_model can be fine tuned by excluding these. -# # # This should typically be done gradually as e.g. -# sync_model_f1 <- fineTuneSyncModel(sync_model, eps_threshold=1E4, silent=TRUE) -# sync_model_f2 <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) -# sync_model_f3 <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) +# # # If the above plots show outliers, sync_model can be fine tuned by excluding these. +# # # Use fineTuneSyncModel() for this. +# # # This should typically be done sequentially using eps_thresholds of e.g. 1E4, 1E3, 1E2, 1E2 +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E3, silent=TRUE) +sync_model <- fineTuneSyncModel(sync_model, eps_threshold=1E2, silent=TRUE) # # # Apply the sync_model to detections data. detections_synced <- applySync(toa=ssu1$detections, hydros=ssu1$hydros, sync_model) @@ -105,7 +120,8 @@ focal_tag <- 15266 rbi_min <- 20 rbi_max <- 40 synced_dat <- detections_synced[tag == focal_tag] -toa <- getToaYaps(synced_dat, hydros_yaps, rbi_min, rbi_max) +toa <- getToaYaps(synced_dat=synced_dat, hydros=hydros_yaps, pingType='rbi', + rbi_min=rbi_min, rbi_max=rbi_max) inp <- getInp(hydros_yaps, toa, E_dist="Mixture", n_ss=5, pingType="rbi", sdInits=1, rbi_min=rbi_min, rbi_max=rbi_max, ss_data_what="est", ss_data=0) @@ -116,6 +132,8 @@ checkInp(inp) yaps_out <- runYaps(inp, silent=TRUE, tmb_smartsearch=TRUE, maxIter=500) # # # Plot the results and compare to "the truth" obtained using gps + +oldpar <- par(no.readonly = TRUE) par(mfrow=c(2,2)) plot(hy~hx, data=hydros_yaps, asp=1, xlab="UTM X", ylab="UTM Y", pch=20, col="green") lines(utm_y~utm_x, data=ssu1$gps, col="blue", lwd=2) @@ -135,6 +153,6 @@ lines(y+2*y_sd~top, data=yaps_out$track, col="red", lty=2) plot(nobs~top, data=yaps_out$track, type="p", main="#detecting hydros per ping") lines(caTools::runmean(nobs, k=10)~top, data=yaps_out$track, col="orange", lwd=2) - +par(oldpar) } } diff --git a/man/simHydros.Rd b/man/simHydros.Rd index 74e80f8..f774552 100644 --- a/man/simHydros.Rd +++ b/man/simHydros.Rd @@ -12,17 +12,17 @@ simHydros(auto = TRUE, trueTrack = NULL) \item{trueTrack}{Track obtained from simTrueTrack().} } \value{ -Dataframe containing X and Y for hydros +\code{data.frame} containing X and Y for hydros } \description{ Sim hydrophone array configuration } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) # Simulate true track of animal movement of n seconds -trueTrack <- simTrueTrack(model='crw', n = 3000, deltaTime=1, shape=1, +trueTrack <- simTrueTrack(model='crw', n = 1000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') # Simulate telemetry observations from true track. @@ -58,7 +58,7 @@ if(pingType == 'sbi'){ pl <- c() maxIter <- ifelse(pingType=="sbi", 500, 5000) -outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) +outTmb <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) # Estimates in pl pl <- outTmb$pl @@ -75,6 +75,5 @@ plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) lines(pl$Y~pl$X, col="red") - } } diff --git a/man/simTelemetryTrack.Rd b/man/simTelemetryTrack.Rd index 7de0ed3..b432243 100644 --- a/man/simTelemetryTrack.Rd +++ b/man/simTelemetryTrack.Rd @@ -25,18 +25,18 @@ simTelemetryTrack( \item{rbi_max}{Minimum and maximum BI for random burst interval transmitters} } \value{ -Data frame containing time of ping and true positions +\code{data.frame} containing time of ping and true positions } \description{ Based on a known true track obtained using simTrueTrack, this function will give true positions at time-of-pings, which are also in the output. TOPs are determined by user-specified transmitter type. Number of pings are determined automatically based on track length and transmitter specifications. } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) # Simulate true track of animal movement of n seconds -trueTrack <- simTrueTrack(model='crw', n = 3000, deltaTime=1, shape=1, +trueTrack <- simTrueTrack(model='crw', n = 1000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') # Simulate telemetry observations from true track. @@ -72,7 +72,7 @@ if(pingType == 'sbi'){ pl <- c() maxIter <- ifelse(pingType=="sbi", 500, 5000) -outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) +outTmb <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) # Estimates in pl pl <- outTmb$pl @@ -89,6 +89,5 @@ plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) lines(pl$Y~pl$X, col="red") - } } diff --git a/man/simToa.Rd b/man/simToa.Rd index 8ff08fe..ab08bbf 100644 --- a/man/simToa.Rd +++ b/man/simToa.Rd @@ -28,11 +28,11 @@ List containing TOA matrix (toa) and matrix indicating, which obs are multipath Provides the TOA matrix for the specified telemetryTrack. Probability of NA (pNA) and observation noise (sigmaToa) can be specified. } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) # Simulate true track of animal movement of n seconds -trueTrack <- simTrueTrack(model='crw', n = 3000, deltaTime=1, shape=1, +trueTrack <- simTrueTrack(model='crw', n = 1000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') # Simulate telemetry observations from true track. @@ -68,7 +68,7 @@ if(pingType == 'sbi'){ pl <- c() maxIter <- ifelse(pingType=="sbi", 500, 5000) -outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) +outTmb <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) # Estimates in pl pl <- outTmb$pl @@ -85,6 +85,5 @@ plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) lines(pl$Y~pl$X, col="red") - } } diff --git a/man/simTrueTrack.Rd b/man/simTrueTrack.Rd index 54d22eb..a1870e4 100644 --- a/man/simTrueTrack.Rd +++ b/man/simTrueTrack.Rd @@ -36,18 +36,18 @@ simTrueTrack( \item{start_pos}{Specify the starting position of the track with c(x0, y0)} } \value{ -Dataframe containing a simulated track +\code{data.frame} containing a simulated track } \description{ Produces a simulated regular time-spaced track following the specified movement model. Linear movement between consecutive observations is assumed. The output contains x, y, time and sound speed at each simulated position. } \examples{ -\dontrun{ +\donttest{ library(yaps) set.seed(42) # Simulate true track of animal movement of n seconds -trueTrack <- simTrueTrack(model='crw', n = 3000, deltaTime=1, shape=1, +trueTrack <- simTrueTrack(model='crw', n = 1000, deltaTime=1, shape=1, scale=0.5, addDielPattern=TRUE, ss='rw') # Simulate telemetry observations from true track. @@ -83,7 +83,7 @@ if(pingType == 'sbi'){ pl <- c() maxIter <- ifelse(pingType=="sbi", 500, 5000) -outTmb <- runTmb(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) +outTmb <- runYaps(inp, maxIter=maxIter, getPlsd=TRUE, getRep=TRUE) # Estimates in pl pl <- outTmb$pl @@ -100,6 +100,5 @@ plot(y~x, data=trueTrack, type="l", xlim=range(hydros$hx), ylim=range(hydros$hy) lines(y~x, data=teleTrack) points(hy~hx, data=hydros, col="green", pch=20, cex=3) lines(pl$Y~pl$X, col="red") - } } diff --git a/man/ssu1.Rd b/man/ssu1.Rd index 4e6a159..b515ca9 100644 --- a/man/ssu1.Rd +++ b/man/ssu1.Rd @@ -7,29 +7,29 @@ \format{ A list containing 3 data.tables: \describe{ - \item{hydros}{ - \itemize{ - \item serial Hydrophone serial number. - \item x,y,z Position of hydrophones in UTM. - \item sync_tag ID of co-located sync tag. Must be identical to entries in data.table detections$tag. - \item idx Unique values from 1:nrow(hydros). - } - } - \item{detections}{ - \itemize{ - \item ts Timestamp of detection in POSIXct(). - \item tag ID of detected tag. - \item epo Timestamp as number of seconds since Unix epoch. Can be obtained using as.numeric(ts). - \item frac Sub-second part of detection timestamp in fractions of second [0-1]. - \item serial Serial number of detecting hydrophone. Must match entry in data.table hydros. - } - } - \item{gps}{ - \itemize{ - \item ts Timestamp of gps position in POSIXct(). - \item utm_x, utm_y Coordinates of position. Same projection and coordinate system as used in hydros. - } - } +\item{hydros}{ +\itemize{ +\item serial Hydrophone serial number. +\item x,y,z Position of hydrophones in UTM. +\item sync_tag ID of co-located sync tag. Must be identical to entries in data.table detections$tag. +\item idx Unique values from 1:nrow(hydros). +} +} +\item{detections}{ +\itemize{ +\item ts Timestamp of detection in POSIXct(). +\item tag ID of detected tag. +\item epo Timestamp as number of seconds since Unix epoch. Can be obtained using as.numeric(ts). +\item frac Sub-second part of detection timestamp in fractions of second (0-1). +\item serial Serial number of detecting hydrophone. Must match entry in data.table hydros. +} +} +\item{gps}{ +\itemize{ +\item ts Timestamp of gps position in POSIXct(). +\item utm_x, utm_y Coordinates of position. Same projection and coordinate system as used in hydros. +} +} } } \usage{ diff --git a/man/tempToSs.Rd b/man/tempToSs.Rd index 3b8be8d..e562f6c 100644 --- a/man/tempToSs.Rd +++ b/man/tempToSs.Rd @@ -14,6 +14,9 @@ tempToSs(temp, sal, depth = 5) \item{depth}{Depth in meters - default = 5 m - can typically be ignored} } +\value{ +Vector of estimated speed of sound in water. +} \description{ Calculate speed of sound from water temperature, salinity and depth Based on H. Medwin (1975) Speed of sound in water: A simple equation for realistic parameters. (https://doi.org/10.1121/1.380790) diff --git a/man/testYaps.Rd b/man/testYaps.Rd index 71542e4..14e33b2 100644 --- a/man/testYaps.Rd +++ b/man/testYaps.Rd @@ -22,30 +22,31 @@ testYaps( \item{est_ss}{Logical whether to test using ss_data_what = 'est' (est_ss = TRUE) or ss_data_what = 'data' (est_ss = FALSE)} -\item{opt_fun}{Which optimization function to use. Default is 'nlminb' - alternative is 'nloptr' (experimental!). If using 'nloptr', `opt_controls` must be specified.} +\item{opt_fun}{Which optimization function to use. Default is \code{opt_fun = 'nlminb'} - alternative is \code{opt_fun = 'nloptr'} (experimental!). If using nloptr, \code{opt_controls} must be specified.} -\item{opt_controls}{List of controls passed to optimization function. For instances, tolerances such as x.tol=1E-8. If opt_fun = 'nloptr', `opt_controls` must be a list formatted appropriately. For instance: opt_controls <- list(algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) ). See `?nloptr` and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in `nloptr` require bounded parameters - see `bounds`.} +\item{opt_controls}{List of controls passed to optimization function. For instances, tolerances such as \code{x.tol=1E-8}. \cr +If \code{opt_fun = 'nloptr'}, \code{opt_controls} must be a list formatted appropriately. For instance: \cr +\code{opt_controls <- list( algorithm="NLOPT_LD_AUGLAG", xtol_abs=1e-12, maxeval=2E+4, print_level = 1, local_opts= list(algorithm="NLOPT_LD_AUGLAG_EQ", xtol_rel=1e-4) )}. \cr +See \code{?nloptr} and the NLopt site https://nlopt.readthedocs.io/en/latest/ for more info. Some algorithms in \code{nloptr} require bounded parameters - see \code{bounds}.} -\item{bounds}{List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) ).} +\item{bounds}{List of two vectors specifying lower and upper bounds of fixed parameters. Length of each vector must be equal to number of fixed parameters. For instance, \code{bounds = list(lb = c(-3, -1, -2), ub = c(2,0,1) )}.} \item{return_yaps}{Logical whether to return the fitted yaps model. Default=FALSE.} -\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see ?TMB::MakeADFun for info). Default and original implementation is TRUE. However, there seems to be an issue with Matrix v1.3.2 that requires tmb_smartsearch=FALSE.} +\item{tmb_smartsearch}{Logical whether to use the TMB smartsearch in the inner optimizer (see \code{?TMB::MakeADFun} for info). Default and original implementation is TRUE. However, there seems to be an issue with recent versions of \code{Matrix} that requires \code{tmb_smartsearch=FALSE}.} +} +\value{ +If \code{return_yaps == TRUE}, the fitted \code{yaps} object. See \code{?runYaps} for further info. } \description{ -Run `testYaps()` to check that the core functions of YAPS is working correctly. +Run \code{testYaps()} to check that the core functions of YAPS is working correctly. Output should be a random simulated (black) and estimated (red) track. } \examples{ -\dontrun{ -# To test basic functionality of yaps using simulated data +#' # To test basic functionality of yaps using simulated data testYaps() # # # Three pingTypes are availabe: -# # # fixed burst interval ('sbi'), -# # # random burst interval with UNKNOWN burst interval sequence('rbi'), -# # # random burst interval with KNOWN burst interval sequence ('pbi') -testYaps(pingType='sbi') -testYaps(pingType='rbi') -testYaps(pingType='pbi') -} +# # # fixed burst interval (testYaps(pingType='sbi')), +# # # random burst interval with UNKNOWN burst interval sequence('testYaps(pingType='rbi')), +# # # random burst interval with KNOWN burst interval sequence (testYaps(pingType='pbi')) } diff --git a/tests/testthat/sync_model_f1_ref.RData b/tests/testthat/sync_model_f1_ref.RData index 49e434996fd5872a89532555a46a766414fba7d5..7931fcfae585a97886ac433715f928fa26b26f0c 100644 GIT binary patch delta 30510 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 delta 30555 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%0A`W+0>EAP$!x#rDq7v;U+>{=cON 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
flJjo-|?M`LmBtH-4@&(kDBXB=G+{vkJ?MG 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 diff --git a/tests/testthat/sync_model_ref.RData b/tests/testthat/sync_model_ref.RData index bf2345cda7400544d9392d3f9ab1af1166553ae6..cf51a5d337ad2147e53c2efe1633179b4630bc5a 100644 GIT binary patch delta 30811 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

q~{q%oiAe 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