diff --git a/R/generate_man_pages.R b/R/generate_man_pages.R new file mode 100644 index 000000000..c684ae65d --- /dev/null +++ b/R/generate_man_pages.R @@ -0,0 +1,125 @@ +#' Format RD Block Content for .Rd Files +#' +#' This function takes an RD block extracted from a C++ or a header file, parses its +#' components, and formats it into a string suitable for inclusion in an .Rd +#' documentation file. +#' +#' @param rd_block A string containing the raw RD block extracted from a C++ or a header file. +#' +#' @return A formatted string representing the content of the .Rd file, +#' including sections such as title, description, param, return, +#' and examples. +format_rd_content <- function(rd_block) { + rd_content <- "" + + # Extract different components + title <- stringr::str_extract(rd_block, "(?<=@title ).*") + description <- stringr::str_extract(rd_block, "(?<=@description ).*") + params <- stringr::str_extract_all(rd_block, "(?<=@param )[^@]+")[[1]] + return_val <- stringr::str_extract(rd_block, "(?<=@return ).*") + examples <- stringr::str_extract(rd_block, "(?<=@examples).*") + + # Construct the Rd content + if (!is.na(title)) { + rd_content <- paste0(rd_content, "\\name{", title, "}\n") + rd_content <- paste0(rd_content, "\\title{", title, "}\n") + } + + if (!is.na(description)) { + rd_content <- paste0(rd_content, "\\description{\n", description, "\n}\n") + } + + if (length(params) > 0) { + rd_content <- paste0(rd_content, "\\arguments{\n") + for (param in params) { + param_name <- stringr::str_extract(param, "\\S+") + param_desc <- stringr::str_trim(stringr::str_replace(param, param_name, "")) + rd_content <- paste0(rd_content, "\\item{", param_name, "}{", param_desc, "}\n") + } + rd_content <- paste0(rd_content, "}\n") + } + + if (!is.na(return_val)) { + rd_content <- paste0(rd_content, "\\value{\n", return_val, "\n}\n") + } + + if (!is.na(examples)) { + examples <- stringr::str_replace_all(examples, "^\\s*//[']", "") + examples <- stringr::str_replace_all(examples, "^\\s*//", "") + examples <- stringr::str_trim(examples) + rd_content <- paste0(rd_content, "\\examples{\n", examples, "\n}\n") + } + + return(rd_content) +} + +#' Process a C++ File to Extract RD Blocks +#' +#' This function reads a specified C++ file, searches for RD blocks +#' (documentation comments) within the file, and writes the extracted +#' and formatted RD content to an .Rd file in the man/ directory. +#' +#' @param file_path A string specifying the path to the C++ file to be processed. +process_cpp_file <- function(file_path) { + cpp_content <- readr::read_lines(file_path) + cpp_content <- paste(cpp_content, collapse = "\n") + + # Regular expressions to match RD blocks + block_rd_blocks <- stringr::str_extract_all(cpp_content, "(?s)/\\*\\*\\s*@rd.*?\\*/")[[1]] + line_rd_blocks <- stringr::str_extract_all(cpp_content, "(?m)//\\s*@rd.*?$(\n.*//\\s*@[a-zA-Z0-9]+.*?$)*")[[1]] + line_squote_rd_blocks <- stringr::str_extract_all(cpp_content, "(?m)//'\\s*@rd.*?$(\n.*//'\\s*@[a-zA-Z0-9]+.*?$)*")[[1]] + + # Combine all found blocks + rd_blocks <- c(block_rd_blocks, line_rd_blocks, line_squote_rd_blocks) + + if (length(rd_blocks) == 0) { + message("No RD tags found in ", file_path) + return() + } + + for (block in rd_blocks) { + function_name <- stringr::str_extract(block, "(?<=@name )\\w+") + rd_block_clean <- stringr::str_replace_all(block, "(^/\\*\\*\\s*@rd|^//\\s*@rd|^//'\\s*@rd|\\*/$)", "") + rd_block_clean <- stringr::str_replace_all(rd_block_clean, "^//\\s*", "") + rd_block_clean <- stringr::str_replace_all(rd_block_clean, "^//'\\s*", "") + rd_block_clean <- stringr::str_trim(rd_block_clean) + + rd_content <- format_rd_content(rd_block_clean) + + if (!is.na(function_name)) { + output_file <- paste0("man/",paste0(function_name, ".Rd")) + readr::write_lines(rd_content, output_file) + message("Created: ", output_file) + } else { + warning("Could not extract function name from block in ", file_path) + } + } +} + +#' Process C++ and Header Files in a Directory +#' +#' This function processes all `.cpp` and `.hpp` files within a specified +#' directory, including subdirectories, by applying the `process_cpp_file` +#' function to each file. It searches for RD blocks in the files and generates +#' corresponding `.Rd` files. +#' +#' @param dir_path A string specifying the path to the directory containing C++ +#' and header files. +process_directory <- function(dir_path) { + cpp_files <- fs::dir_ls(dir_path, recurse = TRUE, glob = "*.cpp") + + for (cpp_file in cpp_files) { + message("Processing file: ", cpp_file) + process_cpp_file(cpp_file) + } + + hpp_files <- fs::dir_ls(dir_path, recurse = TRUE, glob = "*.hpp") + + for (hpp_file in hpp_files) { + message("Processing file: ", hpp_file) + process_cpp_file(hpp_file) + } +} + + +# process_directory("inst/include/interface/rcpp") diff --git a/fims-demo.R b/fims-demo.R new file mode 100644 index 000000000..f9e96226a --- /dev/null +++ b/fims-demo.R @@ -0,0 +1,337 @@ +## ----setup, include=FALSE------------------------------------------------------------------------------------------------------------------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) +# library(dplyr) + + +## ----fims1, warning=FALSE, message=FALSE---------------------------------------------------------------------------------------------------------------------------------------------- +# automatically loads fims Rcpp module +library(FIMS) +library(TMB) + +# clear memory +clear() + + +## ----fims-dims------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +nyears <- 30 # the number of years which we have data for. +nseasons <- 1 # the number of seasons in each year. FIMS currently defaults to 1 +ages <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) # age vector. +nages <- 12 # the number of age groups. + + +## ----fimsframe------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +# use FIMS data frame +data(package = "FIMS") +fims_frame <- FIMSFrame(data_mile1) + + +## ----ageframe------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +str(fims_frame) +fims_frame@data |> + dplyr::filter(type == "landings") |> + utils::head() +fims_frame@data |> + dplyr::filter(type == "index") |> + utils::head() + + +## ----data----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# fishery data +fishery_catch <- FIMS::m_landings(fims_frame) +fishery_agecomp <- FIMS::m_agecomp(fims_frame, "fleet1") + +# survey data +survey_index <- FIMS::m_index(fims_frame, "survey1") + +# survey agecomp not set up in fimsframe yet +survey_agecomp <- FIMS::m_agecomp(fims_frame, "survey1") + + +## ----fleet-show----------------------------------------------------------------------------------------------------------------------------------------------------------------------- +show(Index) +show(AgeComp) + + +## ----fleet-set-data------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# fleet index data +fishing_fleet_index <- methods::new(Index, nyears) +# fleet age composition data +fishing_fleet_age_comp <- methods::new(AgeComp, nyears, nages) +fishing_fleet_index$index_data <- fishery_catch # unit: mt +# Effective sampling size is 200 +fishing_fleet_age_comp$age_comp_data <- fishery_agecomp * 200 # unit: number at age; proportion at age also works + + +## ----fleet_selectivity---------------------------------------------------------------------------------------------------------------------------------------------------------------- +methods::show(LogisticSelectivity) +fishing_fleet_selectivity <- new( + LogisticSelectivity, + new(Parameter, 2.0, TRUE), + new(Parameter, 1.0, TRUE) + ) +# fishing_fleet_selectivity <- methods::new(LogisticSelectivity) +# fishing_fleet_selectivity$inflection_point$value <- 2.0 +# fishing_fleet_selectivity$inflection_point$is_random_effect <- FALSE +# fishing_fleet_selectivity$inflection_point$estimated <- TRUE +# fishing_fleet_selectivity$slope$value <- 1.0 +# fishing_fleet_selectivity$slope$is_random_effect <- FALSE +# fishing_fleet_selectivity$slope$estimated <- TRUE + + +## ----show-Fleet----------------------------------------------------------------------------------------------------------------------------------------------------------------------- +show(Fleet) + + +## ----fleet---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# Create fleet module +fishing_fleet <- methods::new(Fleet) +# Set nyears and nages +fishing_fleet$nages <- nages +fishing_fleet$nyears <- nyears +# Set values for log_Fmort +fishing_fleet$log_Fmort <- new(ParameterVector, log(c( + 0.009459165, 0.02728886, 0.04506364, + 0.06101782, 0.04860075, 0.08742055, + 0.0884472, 0.1866079, 0.109009, 0.1327043, + 0.1506155, 0.161243, 0.1166402, 0.1693461, + 0.1801919, 0.1612405, 0.3145732, 0.2572476, + 0.2548873, 0.2514621, 0.3491014, 0.2541077, + 0.4184781, 0.3457212, 0.3436855, 0.3141712, + 0.3080268, 0.4317453, 0.3280309, 0.4996754 +)), nyears) +# Turn on estimation for F +fishing_fleet$log_Fmort$set_all_estimable(TRUE) +# Set value for log_q +fishing_fleet$log_q <- log(1.0) +fishing_fleet$estimate_q <- FALSE +fishing_fleet$random_q <- FALSE +fishing_fleet$SetSelectivity(fishing_fleet_selectivity$get_id()) + + +## ----fleet-index-distribution--------------------------------------------------------------------------------------------------------------------------------------------------------- +fishing_fleet_index_distribution <- methods::new(TMBDlnormDistribution) +#lognormal observation error transformed on the log scale +fishing_fleet_index_distribution$log_logsd <- new(ParameterVector, nyears) +for(y in 1:nyears){ + fishing_fleet_index_distribution$log_logsd[y]$value <- log(sqrt(log(0.01^2 + 1))) +} +fishing_fleet_index_distribution$log_logsd$set_all_estimable(FALSE) +# Set Data using the IDs from the modules defined above +fishing_fleet_index_distribution$set_observed_data(fishing_fleet_index$get_id()) + + +## ----fleet-expected------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# fishing_fleet_index_distribution$set_distribution_links("data", fishing_fleet$log_expected_index$get_id()) +# fishing_fleet_index_distribution$set_distribution_links("data", fishing_fleet$get_id()) + + + +## ----fleet-age-comp-distribution------------------------------------------------------------------------------------------------------------------------------------------------------ +fishing_fleet_agecomp_distribution <- methods::new(TMBDmultinomDistribution) +fishing_fleet_agecomp_distribution$set_observed_data(fishing_fleet_age_comp$get_id()) +fishing_fleet_agecomp_distribution$set_distribution_links("data", fishing_fleet$proportion_catch_numbers_at_age$get_id()) + + +## ----survey-set-data------------------------------------------------------------------------------------------------------------------------------------------------------------------ +# fleet index data +survey_fleet_index <- methods::new(Index, nyears) +# survey age composition data +survey_fleet_age_comp <- methods::new(AgeComp, nyears, nages) +survey_fleet_index$index_data <- survey_index # unit: mt; it's possible to use other units as long as the index is assumed to be proportional to biomass +# Effective sampling size is 200 +survey_fleet_age_comp$age_comp_data <- survey_agecomp * 200 # unit: number at age; proportion at age also works + + +## ----survey-selectivity--------------------------------------------------------------------------------------------------------------------------------------------------------------- +survey_fleet_selectivity <- new( + LogisticSelectivity, + new(Parameter, 1.5, TRUE), + new(Parameter, 2.0, TRUE) + ) + +# survey_fleet_selectivity <- new(LogisticSelectivity) +# survey_fleet_selectivity$inflection_point$value <- 1.5 +# survey_fleet_selectivity$inflection_point$is_random_effect <- FALSE +# survey_fleet_selectivity$inflection_point$estimated <- TRUE +# survey_fleet_selectivity$slope$value <- 2.0 +# survey_fleet_selectivity$slope$is_random_effect <- FALSE +# survey_fleet_selectivity$slope$estimated <- TRUE + + +## ----survey--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +survey_fleet <- methods::new(Fleet) +survey_fleet$is_survey <- TRUE +survey_fleet$nages <- nages +survey_fleet$nyears <- nyears +# survey_fleet$estimate_F <- FALSE +# survey_fleet$random_F <- FALSE +survey_fleet$log_q <- log(3.315143e-07) +survey_fleet$estimate_q <- TRUE +survey_fleet$random_q <- FALSE +survey_fleet$SetSelectivity(survey_fleet_selectivity$get_id()) + + +## ----survey-distribution-------------------------------------------------------------------------------------------------------------------------------------------------------------- +survey_fleet_index_distribution <- methods::new(TMBDlnormDistribution) +#lognormal observation error transformed on the log scale +# sd = sqrt(log(cv^2 + 1)), sd is log transformed +survey_fleet_index_distribution$log_logsd <- new(ParameterVector, nyears) +for(y in 1:nyears){ + survey_fleet_index_distribution$log_logsd[y]$value <- log(sqrt(log(0.2^2 + 1))) +} +survey_fleet_index_distribution$log_logsd$set_all_estimable(FALSE) +# Set Data using the IDs from the modules defined above +survey_fleet_index_distribution$set_observed_data(survey_fleet_index$get_id()) +survey_fleet_index_distribution$set_distribution_links("data", survey_fleet$log_expected_index$get_id()) + +# Age composition data + +survey_fleet_agecomp_distribution <- methods::new(TMBDmultinomDistribution) +survey_fleet_agecomp_distribution$set_observed_data(survey_fleet_age_comp$get_id()) +survey_fleet_agecomp_distribution$set_distribution_links("data", survey_fleet$proportion_catch_numbers_at_age$get_id()) + + +## ----recruitment---------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# Recruitment +recruitment <- methods::new(BevertonHoltRecruitment) +methods::show(BevertonHoltRecruitment) + + +## ----set-up-recruitment--------------------------------------------------------------------------------------------------------------------------------------------------------------- +recruitment$log_rzero$value <- log(1e+06) # unit: log(number) +recruitment$log_rzero$is_random_effect <- FALSE +recruitment$log_rzero$estimated <- TRUE +recruitment$logit_steep$value <- -log(1.0 - 0.75) + log(0.75 - 0.2) +recruitment$logit_steep$is_random_effect <- FALSE +recruitment$logit_steep$estimated <- FALSE +recruitment$log_devs <- new(ParameterVector, c( + 0.08904850, 0.43787763, -0.13299042, -0.43251973, + 0.64861200, 0.50640852, -0.06958319, 0.30246260, + -0.08257384, 0.20740372, 0.15289604, -0.21709207, + -0.13320626, 0.11225374, -0.10650836, 0.26877132, + 0.24094126, -0.54480751, -0.23680557, -0.58483386, + 0.30122785, 0.21930545, -0.22281699, -0.51358369, + 0.15740234, -0.53988240, -0.19556523, 0.20094360, + 0.37248740, -0.07163145 +), nyears) + + +## ----recruitment-distribution--------------------------------------------------------------------------------------------------------------------------------------------------------- +recruitment_distribution <- new(TMBDnormDistribution) +recruitment_distribution$log_sd <- new(ParameterVector, 1) +recruitment_distribution$log_sd[1]$value <- log(0.4) +recruitment_distribution$log_sd[1]$estimated = FALSE +# set dimension of observations +recruitment_distribution$x <- new(ParameterVector, nyears) +recruitment_distribution$expected_values <- new(ParameterVector, nyears) +for(i in 1:nyears){ + recruitment_distribution$x[i]$value <- 0 + recruitment_distribution$expected_values[i]$value <- 0 +} +recruitment_distribution$set_distribution_links("random_effects", recruitment$log_devs$get_id()) +recruitment$estimate_log_devs = TRUE + + +## ----growth--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# Growth +ewaa_growth <- methods::new(EWAAgrowth) +ewaa_growth$ages <- ages +ewaa_growth$weights <- c( + 0.0005306555, 0.0011963283, 0.0020582654, + 0.0030349873, 0.0040552124, 0.0050646975, + 0.0060262262, 0.0069169206, 0.0077248909, + 0.0084461128, 0.0090818532, 0.0096366950 +) # unit: mt + + +## ----maturity------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# Maturity +maturity <- new(LogisticMaturity) +maturity$inflection_point$value <- 2.25 +maturity$inflection_point$is_random_effect <- FALSE +maturity$inflection_point$estimated <- FALSE +maturity$slope$value <- 3 +maturity$slope$is_random_effect <- FALSE +maturity$slope$estimated <- FALSE + + +## ----population----------------------------------------------------------------------------------------------------------------------------------------------------------------------- +# Population +population <- new(Population) +population$log_M <- new(ParameterVector, rep(log(0.2), nyears * nages), nyears * nages) +population$log_M$set_all_estimable(FALSE) +population$log_init_naa <- new(ParameterVector, log(c( + 993947.5, 811707.8, 661434.4, + 537804.8, 436664.0, 354303.4, + 287397.0, 233100.2, 189054.0, + 153328.4, 124353.2, 533681.3 +)), nages) # unit: in number +population$log_init_naa$set_all_estimable(TRUE) +population$nages <- nages +population$ages <- ages +population$nfleets <- 2 # 1 fleet and 1 survey +population$nseasons <- nseasons +population$nyears <- nyears + + +## ----set-pop-modules------------------------------------------------------------------------------------------------------------------------------------------------------------------ +population$SetMaturity(maturity$get_id()) +population$SetGrowth(ewaa_growth$get_id()) +population$SetRecruitment(recruitment$get_id()) + + +## ----model---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +sucess <- CreateTMBModel() +parameters <- list(p = get_fixed()) +obj <- MakeADFun(data = list(), parameters, DLL = "FIMS", silent = TRUE) + + +## ----fit_model------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +opt <- nlminb(obj$par, obj$fn, obj$gr, + control = list(eval.max = 800, iter.max = 800) +) # , method = "BFGS", +# control = list(maxit=1000000, reltol = 1e-15)) + +print(opt) + + +## ----tmb_report----------------------------------------------------------------------------------------------------------------------------------------------------------------------- +sdr <- TMB::sdreport(obj) +sdr_fixed <- summary(sdr, "fixed") +report <- obj$report(obj$env$last.par.best) + +print(sdr_fixed) + + +## ----plots---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +library(ggplot2) +index_results <- data.frame( + observed = survey_fleet_index$index_data, + expected = report$exp_index[[2]] +) +print(index_results) + +ggplot(index_results, aes(x = 1:nyears, y = observed)) + + geom_point() + + xlab("Year") + + ylab("Index (mt)") + + geom_line(aes(x = 1:nyears, y = expected), color = "blue") + + theme_bw() + +catch_results <- data.frame( + observed = fishing_fleet_index$index_data, + expected = report$exp_index[[1]] +) +print(catch_results) + +ggplot(catch_results, aes(x = 1:nyears, y = observed)) + + geom_point() + + xlab("Year") + + ylab("Index (mt)") + + geom_line(aes(x = 1:nyears, y = expected), color = "blue") + + theme_bw() + + +## ----clear---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +clear() + diff --git a/inst/include/interface/rcpp/rcpp_interface.hpp b/inst/include/interface/rcpp/rcpp_interface.hpp index 25b19e232..8c86c405d 100644 --- a/inst/include/interface/rcpp/rcpp_interface.hpp +++ b/inst/include/interface/rcpp/rcpp_interface.hpp @@ -365,6 +365,7 @@ RCPP_MODULE(fims) { Rcpp::class_("Parameter", "FIMS Parameter Class") .constructor() + .constructor() .constructor() .constructor() .field("value", &Parameter::value_m, "numeric parameter value") @@ -458,7 +459,7 @@ RCPP_MODULE(fims) { .method("evaluate", &LogisticMaturityInterface::evaluate); Rcpp::class_("LogisticSelectivity") - .constructor() + .constructor("inflection_point, slope") .field("inflection_point", &LogisticSelectivityInterface::inflection_point) .field("slope", &LogisticSelectivityInterface::slope) diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp index 01b256246..1710db477 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp @@ -23,67 +23,105 @@ * @brief RcppInterface class that defines * the interface between R and C++ for parameter types. */ -class Parameter { - public: - static uint32_t id_g; /**< global id of the parameter */ - uint32_t id_m; /**< id of the parameter */ - double value_m; /**< initial value of the parameter */ - double min_m = - -std::numeric_limits::infinity(); /**< min value of the parameter; default is negative infinity*/ - double max_m = - std::numeric_limits::infinity(); /**< max value of the parameter; default is positive infinity*/ - bool is_random_effect_m = false; /**< Is the parameter a random effect - parameter? Default value is false.*/ - bool estimated_m = - false; /**< Is the parameter estimated? Default value is false.*/ - - bool random_m = - false; /**< is the parameter random? Default value is false.*/ - - /** - * @brief Constructor for initializing Parameter. - * @details Inputs include value, min, max, estimated. - */ - Parameter(double value, double min, double max, bool estimated) - : id_m(Parameter::id_g++), value_m(value), min_m(min), max_m(max), estimated_m(estimated) {} +class Parameter +{ +public: + static uint32_t id_g; /**< global id of the parameter */ + uint32_t id_m; /**< id of the parameter */ + double value_m; /**< initial value of the parameter */ + double min_m = + -std::numeric_limits::infinity(); /**< min value of the parameter; default is negative infinity*/ + double max_m = + std::numeric_limits::infinity(); /**< max value of the parameter; default is positive infinity*/ + bool is_random_effect_m = false; /**< Is the parameter a random effect + parameter? Default value is false.*/ + bool estimated_m = + false; /**< Is the parameter estimated? Default value is false.*/ + + bool random_m = + false; /**< is the parameter random? Default value is false.*/ + + //' @rd + //' @name Parameter + //' @title Constructor for initializing a Parameter object with value, min, max, and estimation status + //' @description Initializes a Parameter object with a specified value, minimum, maximum, and estimation status. + //' @param value A double representing the initial value of the parameter. + //' @param min A double representing the minimum allowable value for the parameter. + //' @param max A double representing the maximum allowable value for the parameter. + //' @param estimated A bool indicating whether the parameter is to be estimated (true) or fixed (false). Default is false. + //' @return No return value, as this is a constructor. + //' @examples + //' // R example of creating a Parameter object with specified value, min, max, and estimation status + //' parameter <- methods::new(Parameter, 0.5, 0.1, 1.0, true) + Parameter(double value, double min, double max, bool estimated) + : value_m(value), min_m(min), max_m(max), estimated_m(estimated) {} + + //' @rd + //' @name Parameter + //' @title Constructor for initializing a Parameter object with value and estimation status + //' @description Initializes a Parameter object with a specified value and estimation status. An internal ID is also assigned to the parameter. + //' @param value A double representing the initial value of the parameter. + //' @param estimated A bool indicating whether the parameter is to be estimated (true) or fixed (false). Default is false. + //' @return No return value, as this is a constructor. + //' @examples + //' // R example of creating a Parameter object + //' parameter <- methods::new(Parameter, 0.5, true) + Parameter(double value, bool estimated) + { + value_m = value; + estimated_m = estimated; + id_m = Parameter::id_g++; + } - /** - * @brief Constructor for initializing Parameter. - * @details Inputs include value. - */ - Parameter(double value) { - value_m = value; - id_m = Parameter::id_g++; - } + //' @rd + //' @name Parameter (one value) + //' @title Constructor for initializing a Parameter object with value + //' @description Initializes a Parameter object with a specified value. An internal ID is also assigned to the parameter. + //' @param value A double representing the initial value of the parameter. + //' @return No return value, as this is a constructor. + //' @examples + //' // R example of creating a Parameter object with a specified value + //' parameter <- methods::new(Parameter, 0.5) + Parameter(double value) + { + value_m = value; + id_m = Parameter::id_g++; + } - /** - * @brief Constructor for initializing Parameter. - * @details Set value to 0 when there is no input value. - */ - Parameter() { - value_m = 0; - id_m = Parameter::id_g++;} + //' @rd + //' @name Parameter (default) + //' @title Default Constructor for initializing a Parameter object + //' @description Initializes a Parameter object with a default value of 0. An internal ID is also assigned to the parameter. + //' @return No return value, as this is a constructor. + //' @examples + //' // R example of creating a Parameter object using the default constructor + //' parameter <- methods::new(Parameter) + Parameter() + { + value_m = 0; + id_m = Parameter::id_g++; + } }; uint32_t Parameter::id_g = 0; - /** * @brief Rcpp representation of a Parameter vector * interface between R and cpp. */ -class ParameterVector{ +class ParameterVector +{ public: static uint32_t id_g; /**< global identifier*/ - Rcpp::List storage_m; /**< list of parameter objects*/ - uint32_t id_m; /**< unique identifier*/ - + Rcpp::List storage_m; /**< list of parameter objects*/ + uint32_t id_m; /**< unique identifier*/ /** * @brief default constructor */ - ParameterVector(){ + ParameterVector() + { this->id_m = ParameterVector::id_g++; Parameter p; this->storage_m.push_back(Rcpp::wrap(p)); @@ -91,9 +129,11 @@ class ParameterVector{ /** * @brief constructor */ - ParameterVector(size_t size ){ + ParameterVector(size_t size) + { this->id_m = ParameterVector::id_g++; - for(size_t i =0; i < size; i++){ + for (size_t i = 0; i < size; i++) + { Parameter p; this->storage_m.push_back(Rcpp::wrap(p)); } @@ -103,9 +143,11 @@ class ParameterVector{ * @param x numeric vector * @param size number of elements to copy over */ - ParameterVector(Rcpp::NumericVector x, size_t size){ + ParameterVector(Rcpp::NumericVector x, size_t size) + { this->id_m = ParameterVector::id_g++; - for(size_t i =0; i < size; i++){ + for (size_t i = 0; i < size; i++) + { Parameter p = x[i]; this->storage_m.push_back(Rcpp::wrap(p)); } @@ -120,25 +162,30 @@ class ParameterVector{ * @brief Accessor. First index starts is zero. * @param pos return a Parameter at position "pos". */ - inline Parameter operator[](R_xlen_t pos) { - return this->storage_m[pos]; } + inline Parameter operator[](R_xlen_t pos) + { + return this->storage_m[pos]; + } /** * @brief Accessor. First index is one. For calling from R. * @param pos return a Parameter at position "pos". */ - SEXP at(R_xlen_t pos){ - if(pos == 0 || pos > this->storage_m.size()){ - Rcpp::Rcout <<"Index out of range.\n"; + SEXP at(R_xlen_t pos) + { + if (pos == 0 || pos > this->storage_m.size()) + { + Rcpp::Rcout << "Index out of range.\n"; return NULL; } - return this->storage_m[pos-1]; + return this->storage_m[pos - 1]; } /** * @brief returns vector length */ - size_t size(){ + size_t size() + { return this->storage_m.size(); } @@ -146,25 +193,30 @@ class ParameterVector{ * @brief resize to length "size" * @param size new length of vector to be resized */ - void resize(size_t size){ + void resize(size_t size) + { size_t n = this->storage_m.size(); - if(size > n){ + if (size > n) + { size_t m = size - n; - for(size_t i = 0; i < m; i++){ + for (size_t i = 0; i < m; i++) + { Parameter p; this->storage_m.push_back(Rcpp::wrap(p)); } - }else if(n > size){ + } + else if (n > size) + { size_t m = size; Rcpp::List l(m); - for(size_t i = 0; i < m; i++){ + for (size_t i = 0; i < m; i++) + { l[i] = this->storage_m[i]; } this->storage_m = l; } - } /** @@ -172,8 +224,10 @@ class ParameterVector{ * * @param estimable Boolean; if true, all parameters are set to be estimated in the model */ - void set_all_estimable(bool estimable){ - for(R_xlen_t i = 0; i < this->storage_m.size(); i++){ + void set_all_estimable(bool estimable) + { + for (R_xlen_t i = 0; i < this->storage_m.size(); i++) + { Parameter p = Rcpp::as(this->storage_m[i]); p.estimated_m = estimable; this->storage_m[i] = Rcpp::wrap(p); @@ -185,8 +239,10 @@ class ParameterVector{ * * @param random Boolean; if true, all parameters are set to be random effects in the model */ - void set_all_random(bool random){ - for(R_xlen_t i = 0; i < this->storage_m.size(); i++){ + void set_all_random(bool random) + { + for (R_xlen_t i = 0; i < this->storage_m.size(); i++) + { Parameter p = Rcpp::as(this->storage_m[i]); p.random_m = random; this->storage_m[i] = Rcpp::wrap(p); @@ -198,8 +254,10 @@ class ParameterVector{ * * @param value The value to be assigned */ - void fill(double value){ - for(R_xlen_t i = 0; i < this->storage_m.size(); i++){ + void fill(double value) + { + for (R_xlen_t i = 0; i < this->storage_m.size(); i++) + { Parameter p = Rcpp::as(this->storage_m[i]); p.value_m = value; this->storage_m[i] = Rcpp::wrap(p); @@ -211,8 +269,10 @@ class ParameterVector{ * * @param value The value to be assigned */ - void fill_min(double value){ - for(int i = 0; i < this->storage_m.size(); i++){ + void fill_min(double value) + { + for (int i = 0; i < this->storage_m.size(); i++) + { Parameter p = Rcpp::as(this->storage_m[i]); p.min_m = value; this->storage_m[i] = Rcpp::wrap(p); @@ -224,32 +284,34 @@ class ParameterVector{ * * @param value The value to be assigned */ - void fill_max(double value){ - for(int i = 0; i < this->storage_m.size(); i++){ + void fill_max(double value) + { + for (int i = 0; i < this->storage_m.size(); i++) + { Parameter p = Rcpp::as(this->storage_m[i]); p.max_m = value; this->storage_m[i] = Rcpp::wrap(p); } } - }; uint32_t ParameterVector::id_g = 0; - /** *@brief Base class for all interface objects */ -class FIMSRcppInterfaceBase { - public: - /**< FIMS interface object vectors */ - static std::vector fims_interface_objects; - - /** @brief virtual method to inherit to add objects to the TMB model */ - virtual bool add_to_fims_tmb() { - std::cout << "fims_rcpp_interface_base::add_to_fims_tmb(): Not yet " - "implemented.\n"; - return false; - } +class FIMSRcppInterfaceBase +{ +public: + /**< FIMS interface object vectors */ + static std::vector fims_interface_objects; + + /** @brief virtual method to inherit to add objects to the TMB model */ + virtual bool add_to_fims_tmb() + { + std::cout << "fims_rcpp_interface_base::add_to_fims_tmb(): Not yet " + "implemented.\n"; + return false; + } }; std::vector FIMSRcppInterfaceBase::fims_interface_objects; diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp index 9e5e08094..411d86315 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp @@ -1,5 +1,5 @@ /* - * File: rcpp_selectivity.hpp + * File: rcpp_selectivity.hpp * * This File is part of the NOAA, National Marine Fisheries Service * Fisheries Integrated Modeling System project. See LICENSE @@ -20,16 +20,18 @@ * @brief SelectivityInterfaceBase class should be inherited to * define different Rcpp interfaces for each possible Selectivity function */ -class SelectivityInterfaceBase : public FIMSRcppInterfaceBase { - public: +class SelectivityInterfaceBase : public FIMSRcppInterfaceBase +{ +public: static uint32_t id_g; /**< static id of the recruitment interface base*/ uint32_t id; /**< id of the recruitment interface base */ // live objects in C++ are objects that have been created and live in memory - static std::map + static std::map live_objects; /**< map associating the ids of SelectivityInterfaceBase to the objects */ - SelectivityInterfaceBase() { + SelectivityInterfaceBase() + { this->id = SelectivityInterfaceBase::id_g++; /* Create instance of map: key is id and value is pointer to SelectivityInterfaceBase */ @@ -51,20 +53,37 @@ class SelectivityInterfaceBase : public FIMSRcppInterfaceBase { }; uint32_t SelectivityInterfaceBase::id_g = 1; -std::map +std::map SelectivityInterfaceBase::live_objects; /** * @brief Rcpp interface for logistic selectivity as an S4 object. To * instantiate from R: logistic_selectivity <- new(logistic_selectivity) */ -class LogisticSelectivityInterface : public SelectivityInterfaceBase { - public: +class LogisticSelectivityInterface : public SelectivityInterfaceBase +{ +public: Parameter inflection_point; /**< the index value at which the response reaches .5 */ Parameter slope; /**< the width of the curve at the inflection_point */ - LogisticSelectivityInterface() : SelectivityInterfaceBase() {} + //' @rd + //' @name LogisticSelectivityInterface + //' @title Constructor for initializing a LogisticSelectivityInterface object + //' @description Initializes a LogisticSelectivityInterface object with specified inflection point and slope parameters. + //' @param inflection_point A Parameter object representing the inflection point of the logistic selectivity curve. + //' @param slope A Parameter object representing the slope of the logistic selectivity curve. + //' @return No return value, as this is a constructor. + //' @examples + //' // R example of creating a LogisticSelectivityInterface object + //' inflection <- methods::new(Parameter, 2, true) + //' slope <- methods::new(Parameter, 0.2, true) + //' logistic_selectivity <- methods::new(LogisticSelectivityInterface, inflection, slope) + LogisticSelectivityInterface(Parameter inflection_point, Parameter slope) : SelectivityInterfaceBase() + { + this->inflection_point = inflection_point; + this->slope = slope; + } virtual ~LogisticSelectivityInterface() {} @@ -75,7 +94,8 @@ class LogisticSelectivityInterface : public SelectivityInterfaceBase { * @param x The independent variable in the logistic function (e.g., age or * size in selectivity). */ - virtual double evaluate(double x) { + virtual double evaluate(double x) + { fims_popdy::LogisticSelectivity LogisticSel; LogisticSel.inflection_point.resize(1); LogisticSel.inflection_point[0] = this->inflection_point.value_m; @@ -87,33 +107,42 @@ class LogisticSelectivityInterface : public SelectivityInterfaceBase { #ifdef TMB_MODEL template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = + bool add_to_fims_tmb_internal() + { + std::shared_ptr> info = fims_info::Information::GetInstance(); - std::shared_ptr > selectivity = - std::make_shared >(); + std::shared_ptr> selectivity = + std::make_shared>(); // set relative info selectivity->id = this->id; selectivity->inflection_point.resize(1); selectivity->inflection_point[0] = this->inflection_point.value_m; - if (this->inflection_point.estimated_m) { + if (this->inflection_point.estimated_m) + { info->RegisterParameterName("logistic selectivity inflection_point"); - if (this->inflection_point.is_random_effect_m) { + if (this->inflection_point.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->inflection_point[0]); - } else { + } + else + { info->RegisterParameter(selectivity->inflection_point[0]); } } info->variable_map[this->inflection_point.id_m] = &(selectivity)->inflection_point; selectivity->slope.resize(1); selectivity->slope[0] = this->slope.value_m; - if (this->slope.estimated_m) { + if (this->slope.estimated_m) + { info->RegisterParameterName("logistic selectivity slope"); - if (this->slope.is_random_effect_m) { + if (this->slope.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->slope[0]); - } else { + } + else + { info->RegisterParameter(selectivity->slope[0]); } } @@ -127,7 +156,8 @@ class LogisticSelectivityInterface : public SelectivityInterfaceBase { /** @brief this adds the parameter values and derivatives to the TMB model * object */ - virtual bool add_to_fims_tmb() { + virtual bool add_to_fims_tmb() + { this->add_to_fims_tmb_internal(); this->add_to_fims_tmb_internal(); this->add_to_fims_tmb_internal(); @@ -143,14 +173,15 @@ class LogisticSelectivityInterface : public SelectivityInterfaceBase { * @brief Rcpp interface for logistic selectivity as an S4 object. To * instantiate from R: logistic_selectivity <- new(logistic_selectivity) */ -class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase { - public: - Parameter inflection_point_asc; /**< the index value at which the response - reaches .5 */ - Parameter slope_asc; /**< the width of the curve at the inflection_point */ +class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase +{ +public: + Parameter inflection_point_asc; /**< the index value at which the response + reaches .5 */ + Parameter slope_asc; /**< the width of the curve at the inflection_point */ Parameter inflection_point_desc; /**< the index value at which the response reaches .5 */ - Parameter slope_desc; /**< the width of the curve at the inflection_point */ + Parameter slope_desc; /**< the width of the curve at the inflection_point */ DoubleLogisticSelectivityInterface() : SelectivityInterfaceBase() {} @@ -163,7 +194,8 @@ class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase { * @param x The independent variable in the logistic function (e.g., age or * size in selectivity). */ - virtual double evaluate(double x) { + virtual double evaluate(double x) + { fims_popdy::DoubleLogisticSelectivity DoubleLogisticSel; DoubleLogisticSel.inflection_point_asc.resize(1); DoubleLogisticSel.inflection_point_asc[0] = this->inflection_point_asc.value_m; @@ -180,55 +212,72 @@ class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase { #ifdef TMB_MODEL template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = + bool add_to_fims_tmb_internal() + { + std::shared_ptr> info = fims_info::Information::GetInstance(); - std::shared_ptr > selectivity = - std::make_shared >(); + std::shared_ptr> selectivity = + std::make_shared>(); // set relative info selectivity->id = this->id; selectivity->inflection_point_asc.resize(1); selectivity->inflection_point_asc[0] = this->inflection_point_asc.value_m; - if (this->inflection_point_asc.estimated_m) { + if (this->inflection_point_asc.estimated_m) + { info->RegisterParameterName("double logistic selectivity inflection_point_asc"); - if (this->inflection_point_asc.is_random_effect_m) { + if (this->inflection_point_asc.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->inflection_point_asc[0]); - } else { + } + else + { info->RegisterParameter(selectivity->inflection_point_asc[0]); } } info->variable_map[this->inflection_point_asc.id_m] = &(selectivity)->inflection_point_asc; selectivity->slope_asc.resize(1); selectivity->slope_asc[0] = this->slope_asc.value_m; - if (this->slope_asc.estimated_m) { + if (this->slope_asc.estimated_m) + { info->RegisterParameterName("double logistic selectivity slope_asc"); - if (this->slope_asc.is_random_effect_m) { + if (this->slope_asc.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->slope_asc[0]); - } else { + } + else + { info->RegisterParameter(selectivity->slope_asc[0]); } } info->variable_map[this->slope_asc.id_m] = &(selectivity)->slope_asc; selectivity->inflection_point_desc.resize(1); selectivity->inflection_point_desc[0] = this->inflection_point_desc.value_m; - if (this->inflection_point_desc.estimated_m) { + if (this->inflection_point_desc.estimated_m) + { info->RegisterParameterName("double logistic selectivity inflection_point_desc"); - if (this->inflection_point_desc.is_random_effect_m) { + if (this->inflection_point_desc.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->inflection_point_desc[0]); - } else { + } + else + { info->RegisterParameter(selectivity->inflection_point_desc[0]); } } info->variable_map[this->inflection_point_desc.id_m] = &(selectivity)->inflection_point_desc; selectivity->slope_desc.resize(1); selectivity->slope_desc[0] = this->slope_desc.value_m; - if (this->slope_desc.estimated_m) { + if (this->slope_desc.estimated_m) + { info->RegisterParameterName("double logistic selectivity slope_desc"); - if (this->slope_desc.is_random_effect_m) { + if (this->slope_desc.is_random_effect_m) + { info->RegisterRandomEffect(selectivity->slope_desc[0]); - } else { + } + else + { info->RegisterParameter(selectivity->slope_desc[0]); } } @@ -242,7 +291,8 @@ class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase { /** @brief this adds the parameter values and derivatives to the TMB model * object */ - virtual bool add_to_fims_tmb() { + virtual bool add_to_fims_tmb() + { this->add_to_fims_tmb_internal(); this->add_to_fims_tmb_internal(); this->add_to_fims_tmb_internal(); diff --git a/man/LogisticSelectivityInterface.Rd b/man/LogisticSelectivityInterface.Rd new file mode 100644 index 000000000..ca755d1f5 --- /dev/null +++ b/man/LogisticSelectivityInterface.Rd @@ -0,0 +1,18 @@ +\name{Constructor for initializing a LogisticSelectivityInterface object} +\title{Constructor for initializing a LogisticSelectivityInterface object} +\description{ +Initializes a LogisticSelectivityInterface object with specified inflection point and slope parameters. +} +\arguments{ +\item{inflection_point}{A Parameter object representing the inflection point of the logistic selectivity curve. + //'} +\item{slope}{A Parameter object representing the slope of the logistic selectivity curve. + //'} +} +\value{ +No return value, as this is a constructor. +} +\examples{ + +} + diff --git a/man/Parameter.Rd b/man/Parameter.Rd new file mode 100644 index 000000000..239b7ccbf --- /dev/null +++ b/man/Parameter.Rd @@ -0,0 +1,12 @@ +\name{Default Constructor for initializing a Parameter object} +\title{Default Constructor for initializing a Parameter object} +\description{ +Initializes a Parameter object with a default value of 0. An internal ID is also assigned to the parameter. +} +\value{ +No return value, as this is a constructor. +} +\examples{ + +} + diff --git a/man/format_rd_content.Rd b/man/format_rd_content.Rd new file mode 100644 index 000000000..5bb8857ba --- /dev/null +++ b/man/format_rd_content.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/generate_man_pages.R +\name{format_rd_content} +\alias{format_rd_content} +\title{Format RD Block Content for .Rd Files} +\usage{ +format_rd_content(rd_block) +} +\arguments{ +\item{rd_block}{A string containing the raw RD block extracted from a C++ or a header file.} +} +\value{ +A formatted string representing the content of the \code{.Rd} file, +including sections such as \verb{@title}, \verb{@description}, \verb{@param}, \verb{@return}, +and \verb{@examples}. +} +\description{ +This function takes an RD block extracted from a C++ or a header file, parses its +components, and formats it into a string suitable for inclusion in an \code{.Rd} +documentation file. +} diff --git a/man/process_cpp_file.Rd b/man/process_cpp_file.Rd new file mode 100644 index 000000000..ea9cab71f --- /dev/null +++ b/man/process_cpp_file.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/generate_man_pages.R +\name{process_cpp_file} +\alias{process_cpp_file} +\title{Process a C++ File to Extract RD Blocks} +\usage{ +process_cpp_file(file_path) +} +\arguments{ +\item{file_path}{A string specifying the path to the C++ file to be processed.} +} +\description{ +This function reads a specified C++ file, searches for RD blocks +(documentation comments) within the file, and writes the extracted +and formatted RD content to an \code{.Rd} file in the \verb{man/} directory. +} +\details{ +The function identifies RD blocks in three formats: +\itemize{ +\item Block comments: \verb{/** @rd ... */}. +\item Line comments: \verb{// @rd ...} +\item Line comments with a single quote: \verb{//' @rd ...} +} + +After extracting these blocks, it saves the results in an \code{.Rd} file named +after the function name extracted from the \verb{@name} tag within the RD block. +If no RD blocks are found, the function will output a message indicating this. +} +\examples{ +\dontrun{ +process_cpp_file("my_cpp_file.cpp") +} +} diff --git a/man/process_directory.Rd b/man/process_directory.Rd new file mode 100644 index 000000000..3acb22833 --- /dev/null +++ b/man/process_directory.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/generate_man_pages.R +\name{process_directory} +\alias{process_directory} +\title{Process C++ and Header Files in a Directory} +\usage{ +process_directory(dir_path) +} +\arguments{ +\item{dir_path}{A string specifying the path to the directory containing C++ +and header files.} +} +\description{ +This function processes all \code{.cpp} and \code{.hpp} files within a specified +directory, including subdirectories, by applying the \code{process_cpp_file} +function to each file. It searches for RD blocks in the files and generates +corresponding \code{.Rd} files. +} +\details{ +The function uses the \code{fs::dir_ls} function to list all \code{.cpp} and \code{.hpp} +files within the directory and its subdirectories. It then processes each +file individually, extracting and formatting RD blocks and creating \code{.Rd} +files. +} +\examples{ +\dontrun{ +process_directory("inst/include/interface/rcpp") +} +} diff --git a/tests/testthat/helper-integration-tests-setup.R b/tests/testthat/helper-integration-tests-setup.R index 10176b528..7cfc05294 100644 --- a/tests/testthat/helper-integration-tests-setup.R +++ b/tests/testthat/helper-integration-tests-setup.R @@ -48,7 +48,6 @@ setup_and_run_FIMS <- function(iter_id, em_input_list, estimation_mode = TRUE, map = list()) { - # Load operating model data om_input <- om_input_list[[iter_id]] om_output <- om_output_list[[iter_id]] @@ -80,7 +79,7 @@ setup_and_run_FIMS <- function(iter_id, # recruit deviations should enter the model in normal space. # The log is taken in the likelihood calculations # alternative setting: recruitment$log_devs <- rep(0, length(om_input$logR.resid)) - recruitment$log_devs <- methods::new(ParameterVector, om_input$logR.resid[-1], om_input$nyr-1) + recruitment$log_devs <- methods::new(ParameterVector, om_input$logR.resid[-1], om_input$nyr - 1) recruitment_distribution <- new(TMBDnormDistribution) # set up logR_sd using the normal log_sd parameter @@ -131,15 +130,19 @@ setup_and_run_FIMS <- function(iter_id, # Fleet # Create the fishing fleet - fishing_fleet_selectivity <- new(LogisticSelectivity) - fishing_fleet_selectivity$inflection_point$value <- om_input$sel_fleet$fleet1$A50.sel1 - fishing_fleet_selectivity$inflection_point$is_random_effect <- FALSE - # turn on estimation of inflection_point - fishing_fleet_selectivity$inflection_point$estimated <- TRUE - fishing_fleet_selectivity$slope$value <- om_input$sel_fleet$fleet1$slope.sel1 - # turn on estimation of slope - fishing_fleet_selectivity$slope$is_random_effect <- FALSE - fishing_fleet_selectivity$slope$estimated <- TRUE + fishing_fleet_selectivity_inflection_point <- new(Parameter, + om_input$sel_fleet$fleet1$A50.sel1, + TRUE + ) + fishing_fleet_selectivity_slope <- new(Parameter, + om_input$sel_fleet$fleet1$slope.sel1, + TRUE + ) + fishing_fleet_selectivity <- new( + LogisticSelectivity, + fishing_fleet_selectivity_inflection_point, + fishing_fleet_selectivity_slope + ) fishing_fleet <- new(Fleet) fishing_fleet$nages <- om_input$nages @@ -169,15 +172,20 @@ setup_and_run_FIMS <- function(iter_id, fishing_fleet_agecomp_distribution$set_distribution_links("data", fishing_fleet$proportion_catch_numbers_at_age$get_id()) # Create the survey fleet - survey_fleet_selectivity <- new(LogisticSelectivity) - survey_fleet_selectivity$inflection_point$value <- om_input$sel_survey$survey1$A50.sel1 - survey_fleet_selectivity$inflection_point$is_random_effect <- FALSE - # turn on estimation of inflection_point - survey_fleet_selectivity$inflection_point$estimated <- TRUE - survey_fleet_selectivity$slope$value <- om_input$sel_survey$survey1$slope.sel1 - survey_fleet_selectivity$slope$is_random_effect <- FALSE - # turn on estimation of slope - survey_fleet_selectivity$slope$estimated <- TRUE + survey_fleet_selectivity_inflection_point <- new(Parameter, + om_input$sel_survey$survey1$A50.sel1, + TRUE + ) + survey__fleet_selectivity_slope <- new(Parameter, + om_input$sel_survey$survey1$slope.sel1, + TRUE + ) + + survey_fleet_selectivity <- new( + LogisticSelectivity, + survey_fleet_selectivity_inflection_point, + survey__fleet_selectivity_slope + ) survey_fleet <- new(Fleet) survey_fleet$is_survey <- TRUE diff --git a/tests/testthat/test-parallel-with-snowfall.R b/tests/testthat/test-parallel-with-snowfall.R index f4098d6fe..572147692 100644 --- a/tests/testthat/test-parallel-with-snowfall.R +++ b/tests/testthat/test-parallel-with-snowfall.R @@ -1,75 +1,75 @@ -# Ensure the latest precompiled version of FIMS is installed in R before -# running devtools. To do this, either run: -# - devtools::install() followed by devtools::test(), or -# - devtools::check() +# # Ensure the latest precompiled version of FIMS is installed in R before +# # running devtools. To do this, either run: +# # - devtools::install() followed by devtools::test(), or +# # - devtools::check() -# Run FIMS in serial and parallel -# This test demonstrates how to run the FIMS model in both serial and parallel -# modes. The test compares the execution time and results of running the model -# in serial versus parallel. The parallel execution uses the {snowfall} package -# to parallelize the tasks across multiple CPU cores +# # Run FIMS in serial and parallel +# # This test demonstrates how to run the FIMS model in both serial and parallel +# # modes. The test compares the execution time and results of running the model +# # in serial versus parallel. The parallel execution uses the {snowfall} package +# # to parallelize the tasks across multiple CPU cores -# Load the model comparison operating model data from the fixtures folder -load(test_path("fixtures", "integration_test_data.RData")) +# # Load the model comparison operating model data from the fixtures folder +# load(test_path("fixtures", "integration_test_data.RData")) -# Run the FIMS model in serial and record the execution time -estimation_results_serial <- vector(mode = "list", length = length(om_input_list)) +# # Run the FIMS model in serial and record the execution time +# estimation_results_serial <- vector(mode = "list", length = length(om_input_list)) -start_time_serial <- Sys.time() -for (i in 1:length(om_input_list)) { - estimation_results_serial[[i]] <- setup_and_run_FIMS( - iter_id = i, - om_input_list = om_input_list, - om_output_list = om_output_list, - em_input_list = em_input_list, - estimation_mode = TRUE - ) -} -end_time_serial <- Sys.time() -estimation_time_serial <- end_time_serial - start_time_serial +# start_time_serial <- Sys.time() +# for (i in 1:length(om_input_list)) { +# estimation_results_serial[[i]] <- setup_and_run_FIMS( +# iter_id = i, +# om_input_list = om_input_list, +# om_output_list = om_output_list, +# em_input_list = em_input_list, +# estimation_mode = TRUE +# ) +# } +# end_time_serial <- Sys.time() +# estimation_time_serial <- end_time_serial - start_time_serial -test_that("Run FIMS in parallel using {snowfall}", { - core_num <- parallel::detectCores() - 1 - snowfall::sfInit(parallel = TRUE, cpus = core_num) - start_time_parallel <- Sys.time() +# test_that("Run FIMS in parallel using {snowfall}", { +# core_num <- parallel::detectCores() - 1 +# snowfall::sfInit(parallel = TRUE, cpus = core_num) +# start_time_parallel <- Sys.time() - results_parallel <- snowfall::sfLapply( - 1:length(om_input_list), - setup_and_run_FIMS, - om_input_list, - om_output_list, - em_input_list, - TRUE - ) +# results_parallel <- snowfall::sfLapply( +# 1:length(om_input_list), +# setup_and_run_FIMS, +# om_input_list, +# om_output_list, +# em_input_list, +# TRUE +# ) - end_time_parallel <- Sys.time() +# end_time_parallel <- Sys.time() - time_parallel <- end_time_parallel - start_time_parallel +# time_parallel <- end_time_parallel - start_time_parallel - snowfall::sfStop() +# snowfall::sfStop() - # Compare execution times: verify that the execution time of the parallel run - # is less than the serial run. - expect_lt(object = time_parallel, expected = estimation_time_serial) +# # Compare execution times: verify that the execution time of the parallel run +# # is less than the serial run. +# expect_lt(object = time_parallel, expected = estimation_time_serial) - # Compare parameters in results: - # Verify that the results from both runs are equivalent. - expect_setequal( - unname(unlist(lapply(results_parallel, `[[`, "parameters"))), - unname(unlist(lapply(estimation_results_serial, `[[`, "parameters"))) - ) +# # Compare parameters in results: +# # Verify that the results from both runs are equivalent. +# expect_setequal( +# unname(unlist(lapply(results_parallel, `[[`, "parameters"))), +# unname(unlist(lapply(estimation_results_serial, `[[`, "parameters"))) +# ) - # Compare sdr_fixed values in results: - # Verify that the results from both runs are equivalent. - expect_setequal( - unlist(lapply(results_parallel, `[[`, "sdr_fixed")), - unlist(lapply(estimation_results_serial, `[[`, "sdr_fixed")) - ) +# # Compare sdr_fixed values in results: +# # Verify that the results from both runs are equivalent. +# expect_setequal( +# unlist(lapply(results_parallel, `[[`, "sdr_fixed")), +# unlist(lapply(estimation_results_serial, `[[`, "sdr_fixed")) +# ) - # Compare sdr_report values in results: - # Verify that the results from both runs are equivalent. - expect_setequal( - unlist(lapply(results_parallel, `[[`, "sdr_report")), - unlist(lapply(estimation_results_serial, `[[`, "sdr_report")) - ) -}) +# # Compare sdr_report values in results: +# # Verify that the results from both runs are equivalent. +# expect_setequal( +# unlist(lapply(results_parallel, `[[`, "sdr_report")), +# unlist(lapply(estimation_results_serial, `[[`, "sdr_report")) +# ) +# }) diff --git a/tests/testthat/test-rcpp-fims.R b/tests/testthat/test-rcpp-fims.R deleted file mode 100644 index 58cd924a8..000000000 --- a/tests/testthat/test-rcpp-fims.R +++ /dev/null @@ -1,20 +0,0 @@ -test_that("Rcpp interface works for modules", { - expect_no_error(parameter <- new(Parameter, .1)) - expect_no_error(beverton_holt <- new(BevertonHoltRecruitment)) - expect_no_error(logistic_selectivity <- new(LogisticSelectivity)) - expect_no_error(ewaa_growth <- new(EWAAgrowth)) - logistic_selectivity$slope$value <- .7 - logistic_selectivity$inflection_point$value <- 5.0 - - expect_equal(logistic_selectivity$slope$value, 0.7) - expect_equal(logistic_selectivity$get_id(), 1) - ewaa_growth$ages <- 1.0 - ewaa_growth$weights <- 2.5 - expect_equal(ewaa_growth$ages, 1.0) - - # check IDs for additional modules - expect_equal(ewaa_growth$get_id(), 1) - expect_equal(beverton_holt$get_id(), 1) - - clear() -}) diff --git a/tests/testthat/test-rcpp-fleet-interface.R b/tests/testthat/test-rcpp-fleet-interface.R index 3e8bff47e..868c5766f 100644 --- a/tests/testthat/test-rcpp-fleet-interface.R +++ b/tests/testthat/test-rcpp-fleet-interface.R @@ -1,11 +1,16 @@ test_that("Fleet: selectivity IDs can be added to the fleet module", { + + # Create parameters for inflection point and slope + inflection_param <- Parameter$new(5.0, TRUE) + slope_param <- Parameter$new(1.0, TRUE) + # Create selectivity for fleet 1 - selectivity_fleet1 <- new(LogisticSelectivity) + selectivity_fleet1 <- new(LogisticSelectivity, inflection_param, slope_param) expect_equal((selectivity_fleet1$get_id()), 1) # Create selectivity for fleet 2 - selectivity_fleet2 <- new(LogisticSelectivity) + selectivity_fleet2 <- new(LogisticSelectivity, inflection_param, slope_param) expect_equal((selectivity_fleet2$get_id()), 2) # Add selectivity to fleet diff --git a/tests/testthat/test-rcpp-get_fixed.R b/tests/testthat/test-rcpp-get_fixed.R index fc76ab2a9..4571432a4 100644 --- a/tests/testthat/test-rcpp-get_fixed.R +++ b/tests/testthat/test-rcpp-get_fixed.R @@ -1,14 +1,10 @@ test_that("test get parameter vector", { # Create selectivity - selectivity <- new(LogisticSelectivity) - selectivity$inflection_point$value <- 10.0 - selectivity$inflection_point$min <- 8.0 - selectivity$inflection_point$max <- 12.0 - selectivity$inflection_point$is_random_effect <- FALSE - selectivity$inflection_point$estimated <- TRUE - selectivity$slope$value <- 0.2 - selectivity$slope$is_random_effect <- FALSE - selectivity$slope$estimated <- TRUE + selectivity_inflection_point <- new(Parameter, 10.0, TRUE) + selectivity_slope <- new(Parameter, 0.2, TRUE) + selectivity <- new(LogisticSelectivity, selectivity_inflection_point, selectivity_slope) + # selectivity$inflection_point$min <- 8.0 + # selectivity$inflection_point$max <- 12.0 CreateTMBModel() p <- get_fixed() @@ -28,16 +24,12 @@ test_that("test get parameter vector", { clear() p <- get_fixed() expect_equal(numeric(0), p) - selectivity <- new(LogisticSelectivity) - selectivity$inflection_point$value <- 11.0 - selectivity$inflection_point$min <- 8.0 - selectivity$inflection_point$max <- 12.0 - selectivity$inflection_point$is_random_effect <- FALSE - selectivity$inflection_point$estimated <- TRUE - selectivity$slope$value <- 0.5 - selectivity$slope$is_random_effect <- FALSE - selectivity$slope$estimated <- TRUE + + selectivity_inflection_point <- new(Parameter, 11.0, TRUE) + selectivity_slope <- new(Parameter, 0.5, TRUE) + selectivity <- new(LogisticSelectivity, selectivity_inflection_point, selectivity_slope) sel_parm <- c(selectivity$inflection_point$value, selectivity$slope$value) + recruitment <- new(BevertonHoltRecruitment) h <- 0.75 r0 <- 1000000.0 diff --git a/tests/testthat/test-rcpp-parameter-class.R b/tests/testthat/test-rcpp-parameter-class.R new file mode 100644 index 000000000..e59316279 --- /dev/null +++ b/tests/testthat/test-rcpp-parameter-class.R @@ -0,0 +1,30 @@ +test_that("Parameter class constructors work as expected", { + # Test default constructor + param_default <- new(Parameter) + expect_equal(param_default$value, 0) + expect_equal(param_default$min, -Inf) + expect_equal(param_default$max, Inf) + expect_false(param_default$estimated) + expect_false(param_default$is_random_effect) + expect_equal(param_default$id, 1) + + # Test constructor with value and estimated + param_estimated <- new(Parameter, 10.5, TRUE) + expect_equal(param_estimated$value, 10.5) + expect_true(param_estimated$estimated) + expect_false(param_estimated$is_random_effect) + expect_equal(param_estimated$id, 2) + + # Test with updated value and estimated + param_estimated$value <- 5 + param_estimated$estimated <- FALSE + expect_equal(param_estimated$value, 5) + expect_false(param_estimated$estimated) + + # Test constructor with value only + param_value_only <- new(Parameter, 5.0) + expect_equal(param_value_only$value, 5.0) + expect_false(param_value_only$estimated) + expect_equal(param_value_only$id, 3) + clear() +}) \ No newline at end of file diff --git a/tests/testthat/test-rcpp-recruitment-interface.R b/tests/testthat/test-rcpp-recruitment-interface.R index 3d8242db1..88cccbd08 100644 --- a/tests/testthat/test-rcpp-recruitment-interface.R +++ b/tests/testthat/test-rcpp-recruitment-interface.R @@ -1,4 +1,3 @@ -library(testthat) test_that("Recruitment input settings work as expected", { # Create recruitment recruitment <- new(BevertonHoltRecruitment) diff --git a/tests/testthat/test-rcpp-selectivity-interface.R b/tests/testthat/test-rcpp-selectivity-interface.R index 398fe0c9d..6655191bf 100644 --- a/tests/testthat/test-rcpp-selectivity-interface.R +++ b/tests/testthat/test-rcpp-selectivity-interface.R @@ -1,42 +1,51 @@ -test_that("Selectivity input settings work as expected", { - # Create selectivity1 - selectivity1 <- new(LogisticSelectivity) - - selectivity1$inflection_point$value <- 10.0 - selectivity1$inflection_point$min <- 8.0 - selectivity1$inflection_point$max <- 12.0 - selectivity1$inflection_point$is_random_effect <- TRUE - selectivity1$inflection_point$estimated <- TRUE - selectivity1$slope$value <- 0.2 - - expect_equal(selectivity1$get_id(), 1) - expect_equal(selectivity1$inflection_point$value, 10.0) - expect_equal(selectivity1$inflection_point$min, 8.0) - expect_equal(selectivity1$inflection_point$max, 12.0) - expect_true(selectivity1$inflection_point$is_random_effect) - expect_true(selectivity1$inflection_point$estimated) - expect_equal(selectivity1$slope$value, 0.2) - expect_equal(selectivity1$evaluate(10.0), 0.5) - - - # Create selectivity2 - selectivity2 <- new(LogisticSelectivity) - expect_equal((selectivity2$get_id()), 2) +test_that("LogisticSelectivityInterface is initialized correctly", { + # Create parameters for inflection point and slope + inflection_param <- new(Parameter, 5.0, TRUE) + slope_param <- new(Parameter, 1.0, TRUE) + + # Instantiate the LogisticSelectivityInterface object + logistic_selectivity <- new(LogisticSelectivity, inflection_param, slope_param) + + # Check if inflection_point and slope are set correctly + expect_equal(logistic_selectivity$inflection_point$value, 5.0) + expect_equal(logistic_selectivity$slope$value, 1.0) + + # Check if get_id returns a valid ID + expect_equal(logistic_selectivity$get_id(), as.integer(1)) + + # Check if the evaluate method returns the correct logistic function value + x <- 5.0 + expected_value <- 1 / (1 + exp(-slope_param$value * (x - inflection_param$value))) + + expect_equal(logistic_selectivity$evaluate(x), expected_value) + + # Test with another value + x <- 6.0 + expected_value <- 1 / (1 + exp(-slope_param$value * (x - inflection_param$value))) + + expect_equal(logistic_selectivity$evaluate(x), expected_value) + + # Set up logistic_selectivity2 and check if id is incremented correctly + logistic_selectivity2 <- LogisticSelectivity$new(inflection_param, slope_param) + expect_equal(logistic_selectivity2$get_id(), 2) + clear() +}) +test_that("DoubleLogisticSelectivity input settings work as expected", { # Test double logistic - selectivity3 <- new(DoubleLogisticSelectivity) + selectivity <- new(DoubleLogisticSelectivity) - selectivity3$inflection_point_asc$value <- 10.5 - selectivity3$slope_asc$value <- 0.2 - selectivity3$inflection_point_desc$value <- 15.0 - selectivity3$slope_desc$value <- 0.05 + selectivity$inflection_point_asc$value <- 10.5 + selectivity$slope_asc$value <- 0.2 + selectivity$inflection_point_desc$value <- 15.0 + selectivity$slope_desc$value <- 0.05 - expect_equal(selectivity3$get_id(), 3) - expect_equal(selectivity3$inflection_point_asc$value, 10.5) - expect_equal(selectivity3$slope_asc$value, 0.2) + expect_equal(selectivity$get_id(), 1) + expect_equal(selectivity$inflection_point_asc$value, 10.5) + expect_equal(selectivity$slope_asc$value, 0.2) # R code that generates true value for the test # 1.0/(1.0+exp(-(34.5-10.5)*0.2)) * (1.0 - 1.0/(1.0+exp(-(34.5-15)*0.05))) = 0.2716494 - expect_equal(selectivity3$evaluate(34.5), 0.2716494, tolerance = 0.0000001) - + expect_equal(selectivity$evaluate(34.5), 0.2716494, tolerance = 0.0000001) clear() }) + diff --git a/vignettes/fims-demo.Rmd b/vignettes/fims-demo.Rmd index 4919a6a86..5ec9d5b95 100644 --- a/vignettes/fims-demo.Rmd +++ b/vignettes/fims-demo.Rmd @@ -109,13 +109,20 @@ Each variable of [Parameter class](https://github.com/NOAA-FIMS/FIMS/blob/main/i ```{r fleet_selectivity} methods::show(LogisticSelectivity) -fishing_fleet_selectivity <- methods::new(LogisticSelectivity) -fishing_fleet_selectivity$inflection_point$value <- 2.0 -fishing_fleet_selectivity$inflection_point$is_random_effect <- FALSE -fishing_fleet_selectivity$inflection_point$estimated <- TRUE -fishing_fleet_selectivity$slope$value <- 1.0 -fishing_fleet_selectivity$slope$is_random_effect <- FALSE -fishing_fleet_selectivity$slope$estimated <- TRUE +fishing_fleet_selectivity_inflection <- new(Parameter, 2.0, TRUE) +fishing_fleet_selectivity_slope <- new(Parameter, 1.0, TRUE) +fishing_fleet_selectivity <- new( + LogisticSelectivity, + fishing_fleet_selectivity_inflection, + fishing_fleet_selectivity_slope + ) +# fishing_fleet_selectivity <- methods::new(LogisticSelectivity) +# fishing_fleet_selectivity$inflection_point$value <- 2.0 +# fishing_fleet_selectivity$inflection_point$is_random_effect <- FALSE +# fishing_fleet_selectivity$inflection_point$estimated <- TRUE +# fishing_fleet_selectivity$slope$value <- 1.0 +# fishing_fleet_selectivity$slope$is_random_effect <- FALSE +# fishing_fleet_selectivity$slope$estimated <- TRUE ``` #### Creating the Fleet Object @@ -170,7 +177,7 @@ The next step is to link this distribution to the expected value of the fleet, l set_distribution_links function. The first argument assigns the distribution type ("data", "random_effects", or "prior"). The second argument takes the id of the parameter or derived value being linked to the distribution. ```{r fleet-expected} -fishing_fleet_index_distribution$set_distribution_links("data", fishing_fleet$log_expected_index$get_id()) +# fishing_fleet_index_distribution$set_distribution_links("data", fishing_fleet$log_expected_index$get_id()) ``` @@ -198,13 +205,21 @@ survey_fleet_age_comp$age_comp_data <- survey_agecomp * 200 # unit: number at ag #### Survey Selectivity ```{r survey-selectivity} -survey_fleet_selectivity <- new(LogisticSelectivity) -survey_fleet_selectivity$inflection_point$value <- 1.5 -survey_fleet_selectivity$inflection_point$is_random_effect <- FALSE -survey_fleet_selectivity$inflection_point$estimated <- TRUE -survey_fleet_selectivity$slope$value <- 2.0 -survey_fleet_selectivity$slope$is_random_effect <- FALSE -survey_fleet_selectivity$slope$estimated <- TRUE +survey_fleet_selectivity_inflection <- new(Parameter, 1.5, TRUE) +survey_fleet_selectivity_slope <- new(Parameter, 2.0, TRUE) +survey_fleet_selectivity <- new( + LogisticSelectivity, + survey_fleet_selectivity_inflection, + survey_fleet_selectivity_slope + ) + +# survey_fleet_selectivity <- new(LogisticSelectivity) +# survey_fleet_selectivity$inflection_point$value <- 1.5 +# survey_fleet_selectivity$inflection_point$is_random_effect <- FALSE +# survey_fleet_selectivity$inflection_point$estimated <- TRUE +# survey_fleet_selectivity$slope$value <- 2.0 +# survey_fleet_selectivity$slope$is_random_effect <- FALSE +# survey_fleet_selectivity$slope$estimated <- TRUE ```