diff --git a/DESCRIPTION b/DESCRIPTION index 2874b4e9..615de18e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: RstoxBase Version: 2.2.0 -Date: 2026-01-29 +Date: 2026-02-04 Title: Base StoX Functions Authors@R: c( person(given = "Arne Johannes", diff --git a/NEWS.md b/NEWS.md index fccf8b8c..049d7331 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,16 @@ -# RstoxBase v2.2.0-9009 (2026-01-12) +# RstoxBase v2.2.0 (2026-02-04) +* Fixed bug in RegroupLengthDistribution(), where values of IndividualTotalLength were shifted down one length interval. This problem is most apparent when the function argument LengthInterval is the same as the LengthResolution in the input LengthDistributionData. When using the GUI or RstoxFramework::runModel() and similar functions, the precision is rounded to 12 digits, which elliminates this problem for LengthResolution 1 and 0.5 cm. The following table shows the number of lengths between 0 and 1 m that are shifted down when RegroupLengthDistribution() is applied with LengthInterval equal to LengthResolution: +| LengthResolution | Fraction of values shifted down | Mean downwards shift in cm | +|----------|----------|----------| +| 0.1 mm | 357 / 1000 = 0.357 | 0.0357 | +| 0.5 mm | 7 / 200 = 0.035 | 0.0175 | +| 1 cm | 3 / 100 = 0.03 | 0.03 | + +For ICESBiotic data the problem will only occur for StoX projects where data are in 1 mm resolution AND the LengthInterval in RegroupLengthDistribution is 0.1 cm. For Norwegian data the problem is potentially wider as supported length resolutions include 0.1 mm and 0.5 mm as well as 1 mm, 0.5 cm and 1 cm. +* Fixed an issue where exact matching of IndividualTotalLength and LengthResolution did not work in addLengthGroupOneSpecies(), so that the interval matching did all the work. + + +# RstoxBase v2.2.0-9009 (2026-02-02) * Added the new function ReportStationsAlongTransectDesign(). * Fixed bug in PlotTransectDesign() where TrackPointColor did not work. * Re-organized arguments of TransectDesign() to have SurveyDistance before SurveyTime, since SurveyDistance has precedence over SurveyTime. diff --git a/R/Abundance.R b/R/Abundance.R index c6ab342c..749f631d 100644 --- a/R/Abundance.R +++ b/R/Abundance.R @@ -467,7 +467,7 @@ addLengthGroupOneSpecies <- function( # (1) Match the length groups exactly: data[atSpeciesInData, TempLengthGroupUsedInSuperIndividuals := match( - paste(..lengthVar, ..resolutionVar), + paste(eval(get(lengthVar)), eval(get(resolutionVar))), eval( paste( uniqueLengthGroups[[lengthVar]], @@ -559,7 +559,7 @@ addLengthGroup <- function( lengthGroupVar = "TempLengthGroupUsedInSuperIndividuals", warn = TRUE ) { - + # Run a for loop through the common species: speciesVar <- getDataTypeDefinition(dataType = "QuantityData", subTable = "Data", elements = "categoryVariable", unlist = TRUE) speciesInData <- unique(data[[speciesVar]]) diff --git a/R/LengthDistribution.R b/R/LengthDistribution.R index 97e98baf..e05976c1 100644 --- a/R/LengthDistribution.R +++ b/R/LengthDistribution.R @@ -328,7 +328,7 @@ RegroupLengthData <- function( lengthInterval <- getLengthInterval(LengthData, lengthInterval = lengthInterval) # Temporary add the index of the length intervals: - LengthData[, intervalIndex := findInterval(IndividualTotalLength, ..lengthInterval)] + LengthData[, intervalIndex := findInterval_AfterRound(IndividualTotalLength, ..lengthInterval, digits = 10)] # Get the interval widths, and count the number of hits in each interval: lengthIntervalWidths <- diff(lengthInterval) diff --git a/R/Utilities.R b/R/Utilities.R index 168b97cc..a02ddcf7 100644 --- a/R/Utilities.R +++ b/R/Utilities.R @@ -1799,3 +1799,20 @@ convertToNumericIfPossible <- function(x) { + +#' A robust version of findInterval where the inputs are rounded off first to avoid floaring point issues +#' +#' @inheritParams base::findInterval +#' @param digits Integer: The number of digits to round \code{x} and \code{vec} to before applying \code{\link{findInterval}}. +#' @param ... Passed to \code{\link{findInterval}}. +#' +findInterval_AfterRound <- function(x, vec, digits = 10, ...) { + findInterval( + round(x, digits = digits), + round(vec, digits = digits), + ... + ) +} + + + diff --git a/inst/extdata/functionArguments.rds b/inst/extdata/functionArguments.rds index 6fb6679a..3d1f99e6 100644 Binary files a/inst/extdata/functionArguments.rds and b/inst/extdata/functionArguments.rds differ diff --git a/man/findInterval_AfterRound.Rd b/man/findInterval_AfterRound.Rd new file mode 100644 index 00000000..cda1a920 --- /dev/null +++ b/man/findInterval_AfterRound.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Utilities.R +\name{findInterval_AfterRound} +\alias{findInterval_AfterRound} +\title{A robust version of findInterval where the inputs are rounded off first to avoid floaring point issues} +\usage{ +findInterval_AfterRound(x, vec, digits = 10, ...) +} +\arguments{ +\item{x}{numeric.} + +\item{vec}{numeric, sorted (weakly) increasingly, of length \code{N}, + say.} + +\item{digits}{Integer: The number of digits to round \code{x} and \code{vec} to before applying \code{\link{findInterval}}.} + +\item{...}{Passed to \code{\link{findInterval}}.} +} +\description{ +A robust version of findInterval where the inputs are rounded off first to avoid floaring point issues +}