diff --git a/inst/include/common/def.hpp b/inst/include/common/def.hpp index 79ddf8ad3..7d671c7ac 100644 --- a/inst/include/common/def.hpp +++ b/inst/include/common/def.hpp @@ -16,7 +16,7 @@ #include #include #include - +#include "fims_log.hpp" // The following rows initialize default log files for outputing model progress // comments used to assist in diagnosing model issues and tracking progress. // These files will only be created if a logs folder is added to the root model diff --git a/inst/include/common/fims_log.hpp b/inst/include/common/fims_log.hpp new file mode 100644 index 000000000..db4fc19a0 --- /dev/null +++ b/inst/include/common/fims_log.hpp @@ -0,0 +1,527 @@ +#ifndef FIMS_COMMON_LOG +#define FIMS_COMMON_LOG + +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(linux) || defined(__linux) || defined(__linux__) +#define FIMS_LINUX +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#define FIMS_BSD +#elif defined(sun) || defined(__sun) +#define FIMS_SOLARIS +#elif defined(__sgi) +#define FIMS_IRIX +#elif defined(__hpux) +#define FIMS_HPUX +#elif defined(__CYGWIN__) +#define FIMS_CYGWIN +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#define FIMS_WIN32 +#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64) +#define FIMS_WIN64 +#elif defined(__BEOS__) +#define FIMS_BEOS +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#define FIMS_MACOS +#elif defined(__IBMCPP__) || defined(_AIX) +#define FIMS_AIX +#elif defined(__amigaos__) +#define FIMS_AMIGAOS +#elif defined(__QNXNTO__) +#define FIMS_QNXNTO +#endif + +#if defined(FIMS_WIN32) || defined(FIMS_WIN64) +#define FIMS_WINDOWS +#endif + +#ifdef FIMS_WINDOWS +#include +//#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__) +#ifdef FIMS_WINDOWS +#define __PRETTY_FUNCTION__ __FUNCTION__ +#endif +#endif + + + +namespace fims { + + /** + * Log entry. + */ + struct LogEntry { + std::string timestamp; + std::string message; + std::string level; + size_t rank; + std::string user; + std::string wd; + std::string file; + std::string func; + int line; + + /** + * Convert this object to a string. + */ + std::string to_string() { + std::stringstream ss; + ss << "\"timestamp\" : " << "\"" << this->timestamp << "\"" << ",\n"; + ss << "\"level\" : " << "\"" << this->level << "\",\n"; + ss << "\"message\" : " << "\"" << this->message << "\",\n"; + ss << "\"id\" : " << "\"" << this->rank << "\",\n"; + ss << "\"user\" : " << "\"" << this->user << "\",\n"; + ss << "\"wd\" : " << "\"" << this->wd << "\",\n"; + ss << "\"file\" : " << "\"" << this->file << "\",\n"; + ss << "\"routine\" : " << "\"" << this->func << "\",\n"; + ss << "\"line\" : " << "\"" << this->line << "\"\n"; + return ss.str(); + } + + }; + + /** + * FIMS logging class. + */ + class FIMSLog { + std::vector entries; + std::vector log_entries; + size_t entry_number = 0; + std::string path = "fims.log"; + size_t warning_count = 0; + size_t error_count = 0; + + /** + * Get username. + * + * @return username. + */ + std::string get_user() { + char * user; + std::string user_ret = "UNKOWN_USER"; + +#ifdef FIMS_WINDOWS + user = getenv("username"); + user_ret = std::string(user); +#endif +#ifdef FIMS_LINUX + user = getenv("USER"); + user_ret = std::string(user); +#endif + +#ifdef FIMS_MACOS + user = getenv("USER"); + user_ret = std::string(user); +#endif + + return user_ret; + } + public: + bool write_on_exit = true; + bool throw_on_error = false; + static std::shared_ptr fims_log; + + /** + * Default constructor. + */ + FIMSLog() { + + } + + /** + * Destructor. If write_on_exit is set to true, + * the log will be written to the disk in JSON format. + */ + ~FIMSLog() { + if (this->write_on_exit) { + std::ofstream log(this->path); + log << this->get_log(); + log.close(); + } + } + + /** + * Set a path for the log file. + * + * @param path + */ + void set_path(std::string path) { + this->path = path; + } + + /** + * Get the path for the log file. + * + * @return + */ + std::string get_path() { + return this->path; + } + + /** + * Add a "info" level message to the log. + * + * @param str + * @param line + * @param file + * @param func + */ + void info_message(std::string str, int line, const char* file, const char* func) { + + std::filesystem::path cwd =std::filesystem::current_path(); + std::stringstream ss; + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); + + LogEntry l; + l.timestamp = ctime_no_newline; + l.message = str; + l.level = "info"; + l.rank = this->log_entries.size(); + l.user = this->get_user(); + l.wd = cwd.string(); + l.file = file; + l.line = line; + l.func = func; + this->log_entries.push_back(l); + + } + + /** + * Add a "debug" level message to the log. + * + * @param str + * @param line + * @param file + * @param func + */ + void debug_message(std::string str, int line, const char* file, const char* func) { + + std::filesystem::path cwd = std::filesystem::current_path(); + std::stringstream ss; + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); + + LogEntry l; + l.timestamp = ctime_no_newline; + l.message = str; + l.level = "debug"; + l.rank = this->log_entries.size(); + l.user = this->get_user(); + l.wd = cwd.string(); + l.file = file; + l.line = line; + l.func = func; + this->log_entries.push_back(l); + + } + + /** + * Add a "error" level message to the log. + * + * @param str + * @param line + * @param file + * @param func + */ + void error_message(std::string str, int line, const char* file, const char* func) { + this->error_count++; + std::filesystem::path cwd = std::filesystem::current_path(); + + std::stringstream ss; + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); + + LogEntry l; + l.timestamp = ctime_no_newline; + l.message = str; + l.level = "error"; + l.rank = this->log_entries.size(); + l.user = this->get_user(); + l.wd = cwd.string(); + l.file = file; + l.line = line; + l.func = func; + this->log_entries.push_back(l); + + if (this->throw_on_error) { + std::stringstream ss; + ss << "\n\n" << l.to_string() << "\n\n"; + throw std::runtime_error(ss.str().c_str()); + } + + } + + /** + * Add a "warning" level message to the log. + * + * @param str + * @param line + * @param file + * @param func + */ + void warning_message(std::string str, int line, const char* file, const char* func) { + this->warning_count++; + std::filesystem::path cwd = std::filesystem::current_path(); + + std::stringstream ss; + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); + + LogEntry l; + l.timestamp = ctime_no_newline; + l.message = str; + l.level = "warning"; + l.rank = this->log_entries.size(); + l.user = this->get_user(); + l.wd = cwd.string(); + l.file = file; + l.line = line; + l.func = func; + this->log_entries.push_back(l); + + } + + /** + * Get the log as a string. + * + * @return + */ + std::string get_log() { + std::stringstream ss; + if (log_entries.size() == 0) { + ss << "[\n]"; + } else { + ss << "[\n"; + for (size_t i = 0; i < log_entries.size() - 1; i++) { + ss << "{\n" << this->log_entries[i].to_string() << "},\n"; + + } + ss << "{\n" << this->log_entries[log_entries.size() - 1].to_string() << "}\n]"; + } + return ss.str(); + } + + /** + * Return only error entries from the log. + * + * @return + */ + std::string get_errors() { + std::stringstream ss; + std::vector errors; + for (size_t i = 0; i < log_entries.size(); i++) { + if (log_entries[i].level == "error") { + errors.push_back(this->log_entries[i]); + } + } + + if (errors.size() == 0) { + ss << "[\n]"; + } else { + ss << "[\n"; + for (size_t i = 0; i < errors.size() - 1; i++) { + + ss << "{\n" << errors[i].to_string() << "},\n"; + + } + + ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]"; + + } + return ss.str(); + } + + /** + * Return only warning entries from the log. + * + * @return + */ + std::string get_warnings() { + std::stringstream ss; + std::vector warnings; + for (size_t i = 0; i < log_entries.size(); i++) { + if (log_entries[i].level == "warning") { + warnings.push_back(this->log_entries[i]); + } + } + + if (warnings.size() == 0) { + ss << "[\n]"; + } else { + ss << "[\n"; + for (size_t i = 0; i < warnings.size() - 1; i++) { + + ss << "{\n" << warnings[i].to_string() << "},\n"; + + } + + ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]"; + + } + return ss.str(); + } + + /** + * Return only info entries from the log. + * + * @return + */ + std::string get_info() { + std::stringstream ss; + std::vector info; + for (size_t i = 0; i < log_entries.size(); i++) { + if (log_entries[i].level == "info") { + info.push_back(this->log_entries[i]); + } + } + + if (info.size() == 0) { + ss << "[\n]"; + } else { + ss << "[\n"; + for (size_t i = 0; i < info.size() - 1; i++) { + + ss << "{\n" << info[i].to_string() << "},\n"; + + } + + ss << "{\n" << info[info.size() - 1].to_string() << "}\n]"; + + } + return ss.str(); + } + + /** + * Query the log by module. + * + * @param module + * @return + */ + std::string get_module(const std::string& module) { + std::stringstream ss; + std::vector info; + for (size_t i = 0; i < log_entries.size(); i++) { + if (log_entries[i].file.find(module) != std::string::npos) { + info.push_back(this->log_entries[i]); + } + } + + if (info.size() == 0) { + ss << "[\n]"; + } else { + ss << "[\n"; + for (size_t i = 0; i < info.size() - 1; i++) { + + ss << "{\n" << info[i].to_string() << "},\n"; + + } + + ss << "{\n" << info[info.size() - 1].to_string() << "}\n]"; + + } + return ss.str(); + } + + size_t get_error_count() const { + return error_count; + } + + size_t get_warning_count() const { + return warning_count; + } + + + + }; + + + std::shared_ptr FIMSLog::fims_log = std::make_shared(); + +} + +#ifdef FIMS_DEBUG + +#define FIMS_DEBUG_LOG(MESSAGE) FIMSLog::fims_log->debug_message(MESSAGE, __LINE__, __FILE__, __PRETTY_FUNCTION__); + +#else + +#define FIMS_DEBUG_LOG(MESSAGE) + +#endif + +#define FIMS_INFO_LOG(MESSAGE) fims::FIMSLog::fims_log->info_message(MESSAGE, __LINE__, __FILE__, __PRETTY_FUNCTION__); + +#define FIMS_WARNING_LOG(MESSAGE) fims::FIMSLog::fims_log->warning_message(MESSAGE, __LINE__, __FILE__, __PRETTY_FUNCTION__); + +#define FIMS_ERROR_LOG(MESSAGE) fims::FIMSLog::fims_log->error_message(MESSAGE, __LINE__, __FILE__, __PRETTY_FUNCTION__); + +#define FIMS_STR(s) #s + + +namespace fims { + + /** + * Signal intercept function. Writes the log to the disk before + * a crash occurs. + * + * @param sig + */ + void WriteAtExit(int sig) { + + + if (FIMSLog::fims_log->write_on_exit) { + std::ofstream log(FIMSLog::fims_log->get_path()); + log << FIMSLog::fims_log->get_log(); + log.close(); + } + std::signal(sig, SIG_DFL); + raise(sig); + } + + /** + * Converts an object T to a string. + * + * @param v + * @return + */ + template + std::string to_string(T v) { + std::stringstream ss; + ss << v; + return ss.str(); + } + +} + + + +#endif diff --git a/inst/include/interface/rcpp/rcpp_interface.hpp b/inst/include/interface/rcpp/rcpp_interface.hpp index 25b19e232..ac287bf63 100644 --- a/inst/include/interface/rcpp/rcpp_interface.hpp +++ b/inst/include/interface/rcpp/rcpp_interface.hpp @@ -21,488 +21,730 @@ #include "rcpp_objects/rcpp_recruitment.hpp" #include "rcpp_objects/rcpp_selectivity.hpp" #include "rcpp_objects/rcpp_tmb_distribution.hpp" + + +SEXP FIMS_objective_function; +SEXP FIMS_gradient_function; +double FIMS_function_value = 0; +Rcpp::NumericVector FIMS_function_gradient; +double FIMS_mgc_value = 0; +bool FIMS_finalized = false; + /** * @brief Create the TMB model object and add interface objects to it. */ bool CreateTMBModel() { - for (size_t i = 0; i < FIMSRcppInterfaceBase::fims_interface_objects.size(); - i++) { - FIMSRcppInterfaceBase::fims_interface_objects[i]->add_to_fims_tmb(); - } - - // base model - std::shared_ptr> d0 = - fims_info::Information::GetInstance(); - d0->CreateModel(); - - // first-order derivative - std::shared_ptr> d1 = - fims_info::Information::GetInstance(); - d1->CreateModel(); + for (size_t i = 0; i < FIMSRcppInterfaceBase::fims_interface_objects.size(); + i++) { + FIMSRcppInterfaceBase::fims_interface_objects[i]->add_to_fims_tmb(); + } + + // base model + std::shared_ptr> d0 = + fims_info::Information::GetInstance(); + d0->CreateModel(); + + // first-order derivative + std::shared_ptr> d1 = + fims_info::Information::GetInstance(); + d1->CreateModel(); + + // second-order derivative + std::shared_ptr> d2 = + fims_info::Information::GetInstance(); + d2->CreateModel(); + + // third-order derivative + std::shared_ptr> d3 = + fims_info::Information::GetInstance(); + d3->CreateModel(); + + return true; +} - // second-order derivative - std::shared_ptr> d2 = - fims_info::Information::GetInstance(); - d2->CreateModel(); +void SetFIMSFunctions(SEXP fn, SEXP gr) { + FIMS_objective_function = fn; + FIMS_gradient_function = gr; +} - // third-order derivative - std::shared_ptr> d3 = - fims_info::Information::GetInstance(); - d3->CreateModel(); +/** + * @brief Extracts derived quantities from model objects. + */ +void Finalize(Rcpp::NumericVector p) { + FIMS_finalized = true; + std::shared_ptr> information = + fims_info::Information::GetInstance(); + + std::shared_ptr> model = + fims_model::Model::GetInstance(); + + for (size_t i = 0; i < information->fixed_effects_parameters.size(); i++) { + *information->fixed_effects_parameters[i] = p[i]; + } + + model->Evaluate(); + + Rcpp::Function f = Rcpp::as(FIMS_objective_function); + Rcpp::Function g = Rcpp::as(FIMS_gradient_function); + double ret = Rcpp::as(f(p)); + Rcpp::NumericVector grad = Rcpp::as(g(p)); + + FIMS_function_value = ret; + FIMS_function_gradient = grad; + std::cout << "Final value = " << FIMS_function_value << "\nGradient: \n"; + double maxgc = -9999; + for (size_t i = 0; i < FIMS_function_gradient.size(); i++) { + if (std::fabs(FIMS_function_gradient[i]) > maxgc) { + maxgc = std::fabs(FIMS_function_gradient[i]); + } + // std::cout<::population_iterator pit; + // for (pit = information->populations.begin(); pit != information->populations.end(); ++pit) { + // pit->second->Prepare(); + // pit->second->Evaluate(); + // } + // + // fims_info::Information < double>::fleet_iterator fit; + // for (fit = information->fleets.begin(); fit != information->fleets.end(); ++fit) { + // fit->second->Prepare(); + // fit->second->Evaluate(); + //// double ac = fit->second->evaluate_age_comp_nll(); + //// double i = fit->second->evaluate_index_nll(); + // } + + + for (size_t i = 0; i < FIMSRcppInterfaceBase::fims_interface_objects.size(); + i++) { + FIMSRcppInterfaceBase::fims_interface_objects[i]->finalize(); + } +} - return true; +/** + * @brief Extracts derived quantities from model objects. + */ +std::string ToJSON() { + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); + std::shared_ptr> info = + fims_info::Information::GetInstance(); + std::stringstream ss; + ss << "{\n"; + ss << "\"timestamp\": \"" << ctime_no_newline << "\",\n"; + ss << "\"nyears\":" << info->nyears << ",\n"; + ss << "\"nseasons\":" << info->nseasons << ",\n"; + ss << "\"nages\":" << info->nages << ",\n"; + ss << "\"finalized\":" << FIMS_finalized << ",\n"; + ss << "\"objective_function_value\": " << FIMS_function_value << ",\n"; + ss << "\"max_gradient_component\": " << FIMS_mgc_value << ",\n"; + ss << "\"final_gradient\": ["; + for (size_t i = 0; i < FIMS_function_gradient.size() - 1; i++) { + ss << FIMS_function_gradient[i] << ", "; + } + ss << FIMS_function_gradient[FIMS_function_gradient.size() - 1] << "],\n"; + + size_t length = FIMSRcppInterfaceBase::fims_interface_objects.size(); + for (size_t i = 0; i < length - 1; i++) { + ss << FIMSRcppInterfaceBase::fims_interface_objects[i]->to_json() << ",\n"; + } + + ss << FIMSRcppInterfaceBase::fims_interface_objects[length - 1]->to_json() << "\n}"; + return ss.str(); } Rcpp::NumericVector get_fixed_parameters_vector() { - // base model - std::shared_ptr> d0 = - fims_info::Information::GetInstance(); + // base model + std::shared_ptr> d0 = + fims_info::Information::GetInstance(); - Rcpp::NumericVector p; + Rcpp::NumericVector p; - for (size_t i = 0; i < d0->fixed_effects_parameters.size(); i++) { - p.push_back(*d0->fixed_effects_parameters[i]); - } + for (size_t i = 0; i < d0->fixed_effects_parameters.size(); i++) { + p.push_back(*d0->fixed_effects_parameters[i]); + } - return p; + return p; } Rcpp::NumericVector get_random_parameters_vector() { - // base model - std::shared_ptr> d0 = - fims_info::Information::GetInstance(); + // base model + std::shared_ptr> d0 = + fims_info::Information::GetInstance(); - Rcpp::NumericVector p; + Rcpp::NumericVector p; - for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) { - p.push_back(*d0->random_effects_parameters[i]); - } + for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) { + p.push_back(*d0->random_effects_parameters[i]); + } - return p; + return p; } Rcpp::List get_parameter_names(Rcpp::List pars) { - // base model - std::shared_ptr> d0 = - fims_info::Information::GetInstance(); + // base model + std::shared_ptr> d0 = + fims_info::Information::GetInstance(); - pars.attr("names") = d0->parameter_names; + pars.attr("names") = d0->parameter_names; - return pars; + return pars; } /** * Clears the contents of info log file. */ void clear_info_log() { - // First flush the output stream to make sure nothing - // is left in the stream memory bufffer. - INFO_LOG.flush(); - - // Next an new stream is opened and closed to - // overwrite the file. - std::ofstream CLEAR_LOG("logs/info.log"); - CLEAR_LOG.close(); - - // Finally the stream output location is reset back to the start - // of the file. - INFO_LOG.seekp(0); + // First flush the output stream to make sure nothing + // is left in the stream memory bufffer. + INFO_LOG.flush(); + + // Next an new stream is opened and closed to + // overwrite the file. + std::ofstream CLEAR_LOG("logs/info.log"); + CLEAR_LOG.close(); + + // Finally the stream output location is reset back to the start + // of the file. + INFO_LOG.seekp(0); } /** * Clears the contents of fims log file. */ void clear_fims_log() { - FIMS_LOG.flush(); - std::ofstream CLEAR_LOG("logs/fims.log"); - CLEAR_LOG.close(); - FIMS_LOG.seekp(0); + FIMS_LOG.flush(); + std::ofstream CLEAR_LOG("logs/fims.log"); + CLEAR_LOG.close(); + FIMS_LOG.seekp(0); } /** * Clears the contents of data log file. */ void clear_data_log() { - DATA_LOG.flush(); - std::ofstream CLEAR_LOG("logs/data.log"); - CLEAR_LOG.close(); - DATA_LOG.seekp(0); + DATA_LOG.flush(); + std::ofstream CLEAR_LOG("logs/data.log"); + CLEAR_LOG.close(); + DATA_LOG.seekp(0); } /** * Clears the contents of error log file. */ void clear_error_log() { - ERROR_LOG.flush(); - std::ofstream CLEAR_LOG("logs/error.log"); - CLEAR_LOG.close(); - ERROR_LOG.seekp(0); + ERROR_LOG.flush(); + std::ofstream CLEAR_LOG("logs/error.log"); + CLEAR_LOG.close(); + ERROR_LOG.seekp(0); } /** * Clears the contents of model log file. */ void clear_model_log() { - MODEL_LOG.flush(); - std::ofstream CLEAR_LOG("logs/model.log"); - CLEAR_LOG.close(); - MODEL_LOG.seekp(0); + MODEL_LOG.flush(); + std::ofstream CLEAR_LOG("logs/model.log"); + CLEAR_LOG.close(); + MODEL_LOG.seekp(0); } /** * Clears the contents of fleet log file. */ void clear_fleet_log() { - FLEET_LOG.flush(); - std::ofstream CLEAR_LOG("logs/fleet.log"); - CLEAR_LOG.close(); - FLEET_LOG.seekp(0); + FLEET_LOG.flush(); + std::ofstream CLEAR_LOG("logs/fleet.log"); + CLEAR_LOG.close(); + FLEET_LOG.seekp(0); } /** * Clears the contents of population log file. */ void clear_population_log() { - POPULATION_LOG.flush(); - std::ofstream CLEAR_LOG("logs/population.log"); - CLEAR_LOG.close(); - POPULATION_LOG.seekp(0); + POPULATION_LOG.flush(); + std::ofstream CLEAR_LOG("logs/population.log"); + CLEAR_LOG.close(); + POPULATION_LOG.seekp(0); } /** * Clears the contents of maturity log file. */ void clear_maturity_log() { - MATURITY_LOG.flush(); - std::ofstream CLEAR_LOG("logs/maturity.log"); - CLEAR_LOG.close(); - MATURITY_LOG.seekp(0); + MATURITY_LOG.flush(); + std::ofstream CLEAR_LOG("logs/maturity.log"); + CLEAR_LOG.close(); + MATURITY_LOG.seekp(0); } /** * Clears the contents of recruitment log file. */ void clear_recruitment_log() { - RECRUITMENT_LOG.flush(); - std::ofstream CLEAR_LOG("logs/recruitment.log"); - CLEAR_LOG.close(); - RECRUITMENT_LOG.seekp(0); + RECRUITMENT_LOG.flush(); + std::ofstream CLEAR_LOG("logs/recruitment.log"); + CLEAR_LOG.close(); + RECRUITMENT_LOG.seekp(0); } /** * Clears the contents of growth log file. */ void clear_growth_log() { - GROWTH_LOG.flush(); - std::ofstream CLEAR_LOG("logs/growth.log"); - CLEAR_LOG.close(); - GROWTH_LOG.seekp(0); + GROWTH_LOG.flush(); + std::ofstream CLEAR_LOG("logs/growth.log"); + CLEAR_LOG.close(); + GROWTH_LOG.seekp(0); } /** * Clears the contents of selectivity log file. */ void clear_selectivity_log() { - SELECTIVITY_LOG.flush(); - std::ofstream CLEAR_LOG("logs/selectivity.log"); - CLEAR_LOG.close(); - SELECTIVITY_LOG.seekp(0); + SELECTIVITY_LOG.flush(); + std::ofstream CLEAR_LOG("logs/selectivity.log"); + CLEAR_LOG.close(); + SELECTIVITY_LOG.seekp(0); } /** * Clears the contents of debug log file. */ void clear_debug_log() { - DEBUG_LOG.flush(); - std::ofstream CLEAR_LOG("logs/debug/debug.log"); - CLEAR_LOG.close(); - DEBUG_LOG.seekp(0); + DEBUG_LOG.flush(); + std::ofstream CLEAR_LOG("logs/debug/debug.log"); + CLEAR_LOG.close(); + DEBUG_LOG.seekp(0); } /** * Clears the contents of distributions log file. */ void clear_distributions_log() { - DISTRIBUTIONS_LOG.flush(); - std::ofstream CLEAR_LOG("logs/distributions.log"); - CLEAR_LOG.close(); - DISTRIBUTIONS_LOG.seekp(0); + DISTRIBUTIONS_LOG.flush(); + std::ofstream CLEAR_LOG("logs/distributions.log"); + CLEAR_LOG.close(); + DISTRIBUTIONS_LOG.seekp(0); } /** * Clears the contents of log files. */ void clear_logs() { - clear_fims_log(); - clear_info_log(); - clear_data_log(); - clear_error_log(); - clear_model_log(); - clear_fleet_log(); - clear_population_log(); - clear_recruitment_log(); - clear_growth_log(); - clear_maturity_log(); - clear_selectivity_log(); - clear_debug_log(); - clear_distributions_log(); + clear_fims_log(); + clear_info_log(); + clear_data_log(); + clear_error_log(); + clear_model_log(); + clear_fleet_log(); + clear_population_log(); + clear_recruitment_log(); + clear_growth_log(); + clear_maturity_log(); + clear_selectivity_log(); + clear_debug_log(); + clear_distributions_log(); } template void clear_internal() { - std::shared_ptr> d0 = - fims_info::Information::GetInstance(); - d0->fixed_effects_parameters.clear(); - d0->random_effects_parameters.clear(); - d0->variable_map.clear(); + std::shared_ptr> d0 = + fims_info::Information::GetInstance(); + d0->fixed_effects_parameters.clear(); + d0->random_effects_parameters.clear(); + d0->variable_map.clear(); } + /** * Clears the vector of independent variables. */ void clear() { - // rcpp_interface_base.hpp - FIMSRcppInterfaceBase::fims_interface_objects.clear(); + // rcpp_interface_base.hpp + FIMSRcppInterfaceBase::fims_interface_objects.clear(); + + //Parameter and ParameterVector + Parameter::id_g = 1; + ParameterVector::id_g = 1; + // rcpp_data.hpp + DataInterfaceBase::id_g = 1; + DataInterfaceBase::live_objects.clear(); - //Parameter and ParameterVector - Parameter::id_g = 1; - ParameterVector::id_g = 1; - // rcpp_data.hpp - DataInterfaceBase::id_g = 1; - DataInterfaceBase::live_objects.clear(); + AgeCompDataInterface::id_g = 1; + AgeCompDataInterface::live_objects.clear(); - AgeCompDataInterface::id_g = 1; - AgeCompDataInterface::live_objects.clear(); + IndexDataInterface::id_g = 1; + IndexDataInterface::live_objects.clear(); - IndexDataInterface::id_g = 1; - IndexDataInterface::live_objects.clear(); + // rcpp_fleets.hpp + FleetInterfaceBase::id_g = 1; + FleetInterfaceBase::live_objects.clear(); - // rcpp_fleets.hpp - FleetInterfaceBase::id_g = 1; - FleetInterfaceBase::live_objects.clear(); + FleetInterface::id_g = 1; + FleetInterface::live_objects.clear(); - FleetInterface::id_g = 1; - FleetInterface::live_objects.clear(); + // rcpp_growth.hpp + GrowthInterfaceBase::id_g = 1; + GrowthInterfaceBase::live_objects.clear(); - // rcpp_growth.hpp - GrowthInterfaceBase::id_g = 1; - GrowthInterfaceBase::live_objects.clear(); + EWAAGrowthInterface::id_g = 1; + EWAAGrowthInterface::live_objects.clear(); - EWAAGrowthInterface::id_g = 1; - EWAAGrowthInterface::live_objects.clear(); + // rcpp_maturity.hpp + MaturityInterfaceBase::id_g = 1; + MaturityInterfaceBase::live_objects.clear(); - // rcpp_maturity.hpp - MaturityInterfaceBase::id_g = 1; - MaturityInterfaceBase::live_objects.clear(); + LogisticMaturityInterface::id_g = 1; + LogisticMaturityInterface::live_objects.clear(); - LogisticMaturityInterface::id_g = 1; - LogisticMaturityInterface::live_objects.clear(); + // rcpp_population.hpp + PopulationInterfaceBase::id_g = 1; + PopulationInterfaceBase::live_objects.clear(); - // rcpp_population.hpp - PopulationInterfaceBase::id_g = 1; - PopulationInterfaceBase::live_objects.clear(); + PopulationInterface::id_g = 1; + PopulationInterface::live_objects.clear(); + + // rcpp_recruitment.hpp + RecruitmentInterfaceBase::id_g = 1; + RecruitmentInterfaceBase::live_objects.clear(); + + BevertonHoltRecruitmentInterface::id_g = 1; + BevertonHoltRecruitmentInterface::live_objects.clear(); + + // rcpp_selectivity.hpp + SelectivityInterfaceBase::id_g = 1; + SelectivityInterfaceBase::live_objects.clear(); + + LogisticSelectivityInterface::id_g = 1; + LogisticSelectivityInterface::live_objects.clear(); + + DoubleLogisticSelectivityInterface::id_g = 1; + DoubleLogisticSelectivityInterface::live_objects.clear(); + + // rcpp_tmb_distribution.hpp + DistributionsInterfaceBase::id_g = 1; + DistributionsInterfaceBase::live_objects.clear(); + + DnormDistributionsInterface::id_g = 1; + DnormDistributionsInterface::live_objects.clear(); + + DlnormDistributionsInterface::id_g = 1; + DlnormDistributionsInterface::live_objects.clear(); + + DmultinomDistributionsInterface::id_g = 1; + DmultinomDistributionsInterface::live_objects.clear(); + + clear_internal(); + clear_internal(); + clear_internal(); + clear_internal(); + + FIMS_finalized = false; +} + +/** + * Returns the entire log as a string in JSON format. + */ +std::string get_log() { + return fims::FIMSLog::fims_log->get_log(); +} - PopulationInterface::id_g = 1; - PopulationInterface::live_objects.clear(); +/** + * Returns only error entries from log as a string in JSON format. + */ +std::string get_log_errors() { + return fims::FIMSLog::fims_log->get_errors(); +} - // rcpp_recruitment.hpp - RecruitmentInterfaceBase::id_g = 1; - RecruitmentInterfaceBase::live_objects.clear(); +/** + * Returns only warning entries from log as a string in JSON format. + */ +std::string get_log_warnings() { + return fims::FIMSLog::fims_log->get_warnings(); +} - BevertonHoltRecruitmentInterface::id_g = 1; - BevertonHoltRecruitmentInterface::live_objects.clear(); +/** + * Returns only info entries from log as a string in JSON format. + */ +std::string get_log_info() { + return fims::FIMSLog::fims_log->get_info(); +} - // rcpp_selectivity.hpp - SelectivityInterfaceBase::id_g = 1; - SelectivityInterfaceBase::live_objects.clear(); +/** + * Returns log entries by module as a string in JSON format. + */ +std::string get_log_module(const std::string& module) { + return fims::FIMSLog::fims_log->get_module(module); +} - LogisticSelectivityInterface::id_g = 1; - LogisticSelectivityInterface::live_objects.clear(); +/** + * If true, writes the log on exit . + */ +void write_log(bool write) { + FIMS_INFO_LOG("Setting FIMS write log: " + fims::to_string(write)); + fims::FIMSLog::fims_log->write_on_exit = write; +} - DoubleLogisticSelectivityInterface::id_g = 1; - DoubleLogisticSelectivityInterface::live_objects.clear(); +/** + * Sets the path for the log file to written. + */ +void set_log_path(const std::string& path) { + FIMS_INFO_LOG("Setting FIMS log path: " + path); + fims::FIMSLog::fims_log->set_path(path); +} - // rcpp_tmb_distribution.hpp - DistributionsInterfaceBase::id_g = 1; - DistributionsInterfaceBase::live_objects.clear(); +/** + * If true, throws a runtime exception when an error is logged . + */ +void set_log_throw_on_error(bool throw_on_error) { + fims::FIMSLog::fims_log->throw_on_error = throw_on_error; +} - DnormDistributionsInterface::id_g = 1; - DnormDistributionsInterface::live_objects.clear(); +/** + * Initializes the logging system, sets all signal handling. + */ +void init_logging() { + + FIMS_INFO_LOG("Initializing FIMS logging system."); + std::signal(SIGSEGV, &fims::WriteAtExit); + std::signal(SIGINT, &fims::WriteAtExit); + std::signal(SIGABRT, &fims::WriteAtExit); + std::signal(SIGFPE, &fims::WriteAtExit); + std::signal(SIGILL, &fims::WriteAtExit); + std::signal(SIGTERM, &fims::WriteAtExit); +} - DlnormDistributionsInterface::id_g = 1; - DlnormDistributionsInterface::live_objects.clear(); +/** + * Add log info entry from R. + */ +void log_info(std::string log_entry) { + fims::FIMSLog::fims_log->info_message(log_entry, -1, "R_env", "R_script_entry"); +} - DmultinomDistributionsInterface::id_g = 1; - DmultinomDistributionsInterface::live_objects.clear(); +/** + * Add log warning entry from R. + */ +void log_warning(std::string log_entry) { + fims::FIMSLog::fims_log->warning_message(log_entry, -1, "R_env", "R_script_entry"); +} - clear_internal(); - clear_internal(); - clear_internal(); - clear_internal(); +/** + * Add log error entry from R. + */ +void log_error(std::string log_entry) { + + std::stringstream ss; + ss << "capture.output(traceback(4))"; + SEXP expression, result; + ParseStatus status; + + PROTECT(expression = R_ParseVector(Rf_mkString(ss.str().c_str()), 1, &status, R_NilValue)); + if (status != PARSE_OK) { + std::cout << "Error parsing expression" << std::endl; + UNPROTECT(1); + } + Rcpp::Rcout << "before call."; + PROTECT(result = Rf_eval(VECTOR_ELT(expression, 0), R_GlobalEnv)); + Rcpp::Rcout << "after call."; + UNPROTECT(2); + std::stringstream ss_ret; + ss_ret << "traceback:\n"; + for (int j = 0; j < LENGTH(result); j++) { + std::string str(CHAR(STRING_ELT(result, j))); + ss_ret << str << "\n"; + } + + std::string ret = ss_ret.str(); //"find error";//Rcpp::as(result); + + + // Rcpp::Environment base = Rcpp::Environment::global_env(); + // Rcpp::Function f = base["traceback"]; + // std::string ret = Rcpp::as(f()); + fims::FIMSLog::fims_log->error_message(log_entry, -1, "R_env", ret.c_str()); } RCPP_EXPOSED_CLASS(Parameter) RCPP_EXPOSED_CLASS(ParameterVector) RCPP_MODULE(fims) { - Rcpp::function("CreateTMBModel", &CreateTMBModel); - Rcpp::function("get_fixed", &get_fixed_parameters_vector); - Rcpp::function("get_random", &get_random_parameters_vector); - Rcpp::function("get_parameter_names", &get_parameter_names); - Rcpp::function("clear", clear); - Rcpp::function("clear_logs", clear_logs); - Rcpp::function("clear_fims_log", clear_fims_log); - Rcpp::function("clear_info_log", clear_info_log); - Rcpp::function("clear_error_log", clear_error_log); - Rcpp::function("clear_data_log", clear_data_log); - Rcpp::function("clear_population_log", clear_population_log); - Rcpp::function("clear_model_log", clear_model_log); - Rcpp::function("clear_recruitment_log", clear_recruitment_log); - Rcpp::function("clear_fleet_log", clear_fleet_log); - Rcpp::function("clear_growth_log", clear_growth_log); - Rcpp::function("clear_maturity_log", clear_maturity_log); - Rcpp::function("clear_selectivity_log", clear_selectivity_log); - Rcpp::function("clear_debug_log", clear_debug_log); - - Rcpp::class_("Parameter", "FIMS Parameter Class") - .constructor() - .constructor() - .constructor() - .field("value", &Parameter::value_m, "numeric parameter value") - .field("min", &Parameter::min_m, "minimum parameter value") - .field("max", &Parameter::max_m, "maximum parameter value") - .field("id", &Parameter::id_m, "unique id for parameter class") - .field("is_random_effect", &Parameter::is_random_effect_m, "boolean indicating whether or not parameter is a random effect; default value is FALSE") - .field("estimated", &Parameter::estimated_m, "boolean indicating whether or not parameter is estimated; default value is FALSE"); - - Rcpp::class_("ParameterVector") - .constructor() - .constructor() - .constructor() - .field("data", &ParameterVector::storage_m, "list where each element is a Parameter class") - .method("at", &ParameterVector::at, "returns a Parameter at the indicated position given the index argument") - .method("size", &ParameterVector::size, "returns the size of the Parameter Vector") - .method("resize", &ParameterVector::resize, "resizes the Parameter Vector given the provided length argument") - .method("set_all_estimable", &ParameterVector::set_all_estimable, "sets all Parameters within vector as estimable") - .method("set_all_random", &ParameterVector::set_all_random, "sets all Parameters within vector as estimable") - .method("fill", &ParameterVector::fill, "sets the value of all Parameters in the vector with the provided value") - .method("get_id", &ParameterVector::get_id, "get the ID of the interface base object."); - - Rcpp::class_("BevertonHoltRecruitment") - .constructor() - .field("logit_steep", &BevertonHoltRecruitmentInterface::logit_steep) - .field("log_rzero", &BevertonHoltRecruitmentInterface::log_rzero) - .field("log_devs", &BevertonHoltRecruitmentInterface::log_devs) - .field("estimate_log_devs", - &BevertonHoltRecruitmentInterface::estimate_log_devs) - .method("get_id", &BevertonHoltRecruitmentInterface::get_id) - .field("log_sigma_recruit", - &BevertonHoltRecruitmentInterface::log_sigma_recruit) - .method("evaluate", &BevertonHoltRecruitmentInterface::evaluate); - - Rcpp::class_("Fleet") - .constructor() - .field("is_survey", &FleetInterface::is_survey) - .field("log_q", &FleetInterface::log_q) - .field("log_Fmort", &FleetInterface::log_Fmort) - .field("nages", &FleetInterface::nages) - .field("nyears", &FleetInterface::nyears) - .field("estimate_q", &FleetInterface::estimate_q) - .field("random_q", &FleetInterface::random_q) - .field("log_expected_index", &FleetInterface::log_expected_index) - .field("proportion_catch_numbers_at_age", &FleetInterface::proportion_catch_numbers_at_age) - .method("SetSelectivity", &FleetInterface::SetSelectivity); - - Rcpp::class_("AgeComp") - .constructor() - .field("age_comp_data", &AgeCompDataInterface::age_comp_data) - .method("get_id", &AgeCompDataInterface::get_id); - - Rcpp::class_("Index") - .constructor() - .field("index_data", &IndexDataInterface::index_data) - .method("get_id", &IndexDataInterface::get_id); - - Rcpp::class_("Population") - .constructor() - .method("get_id", &PopulationInterface::get_id) - .field("nages", &PopulationInterface::nages) - .field("nfleets", &PopulationInterface::nfleets) - .field("nseasons", &PopulationInterface::nseasons) - .field("nyears", &PopulationInterface::nyears) - .field("log_M", &PopulationInterface::log_M) - .field("log_init_naa", &PopulationInterface::log_init_naa) - .field("proportion_female", &PopulationInterface::proportion_female) - .field("ages", &PopulationInterface::ages) - .field("estimate_prop_female", &PopulationInterface::estimate_prop_female) - .method("evaluate", &PopulationInterface::evaluate) - .method("SetMaturity", &PopulationInterface::SetMaturity) - .method("SetGrowth", &PopulationInterface::SetGrowth) - .method("SetRecruitment", &PopulationInterface::SetRecruitment) - .method("evaluate", &PopulationInterface::evaluate); - - Rcpp::class_("TMBDnormDistribution") - .constructor() - .method("get_id", &DnormDistributionsInterface::get_id) - .method("evaluate", &DnormDistributionsInterface::evaluate) - .method("set_observed_data", &DnormDistributionsInterface::set_observed_data) - .method("set_distribution_links", &DnormDistributionsInterface::set_distribution_links) - .field("x", &DnormDistributionsInterface::x) - .field("expected_values", &DnormDistributionsInterface::expected_values) - .field("log_sd", &DnormDistributionsInterface::log_sd); - - Rcpp::class_("LogisticMaturity") - .constructor() - .field("inflection_point", &LogisticMaturityInterface::inflection_point) - .field("slope", &LogisticMaturityInterface::slope) - .method("get_id", &LogisticMaturityInterface::get_id) - .method("evaluate", &LogisticMaturityInterface::evaluate); - - Rcpp::class_("LogisticSelectivity") - .constructor() - .field("inflection_point", - &LogisticSelectivityInterface::inflection_point) - .field("slope", &LogisticSelectivityInterface::slope) - .method("get_id", &LogisticSelectivityInterface::get_id) - .method("evaluate", &LogisticSelectivityInterface::evaluate); - - Rcpp::class_("DoubleLogisticSelectivity") - .constructor() - .field("inflection_point_asc", - &DoubleLogisticSelectivityInterface::inflection_point_asc) - .field("slope_asc", &DoubleLogisticSelectivityInterface::slope_asc) - .field("inflection_point_desc", - &DoubleLogisticSelectivityInterface::inflection_point_desc) - .field("slope_desc", &DoubleLogisticSelectivityInterface::slope_desc) - .method("get_id", &DoubleLogisticSelectivityInterface::get_id) - .method("evaluate", &DoubleLogisticSelectivityInterface::evaluate); - - Rcpp::class_("EWAAgrowth") - .constructor() - .field("ages", &EWAAGrowthInterface::ages) - .field("weights", &EWAAGrowthInterface::weights) - .method("get_id", &EWAAGrowthInterface::get_id) - .method("evaluate", &EWAAGrowthInterface::evaluate); - - Rcpp::class_("TMBDlnormDistribution") - .constructor() - .method("get_id", &DlnormDistributionsInterface::get_id) - .method("evaluate", &DlnormDistributionsInterface::evaluate) - .method("set_observed_data", &DlnormDistributionsInterface::set_observed_data) - .method("set_distribution_links", &DlnormDistributionsInterface::set_distribution_links) - .field("input_type", &DlnormDistributionsInterface::input_type) - .field("x", &DlnormDistributionsInterface::x) - .field("expected_values", &DlnormDistributionsInterface::expected_values) - .field("log_logsd", &DlnormDistributionsInterface::log_logsd); - - Rcpp::class_("TMBDmultinomDistribution") - .constructor() - .method("evaluate", &DmultinomDistributionsInterface::evaluate) - .method("get_id", &DmultinomDistributionsInterface::get_id) - .method("set_observed_data", &DmultinomDistributionsInterface::set_observed_data) - .method("set_distribution_links", &DmultinomDistributionsInterface::set_distribution_links) - .field("x", &DmultinomDistributionsInterface::x) - .field("expected_values", &DmultinomDistributionsInterface::expected_values) - .field("dims", &DmultinomDistributionsInterface::dims); + Rcpp::function("CreateTMBModel", &CreateTMBModel); + Rcpp::function("SetFIMSFunctions", &SetFIMSFunctions); + Rcpp::function("Finalize", &Finalize); + Rcpp::function("ToJSON", &ToJSON); + Rcpp::function("get_fixed", &get_fixed_parameters_vector); + Rcpp::function("get_random", &get_random_parameters_vector); + Rcpp::function("get_parameter_names", &get_parameter_names); + Rcpp::function("clear", clear); + Rcpp::function("clear_logs", clear_logs); + Rcpp::function("clear_fims_log", clear_fims_log); + Rcpp::function("clear_info_log", clear_info_log); + Rcpp::function("clear_error_log", clear_error_log); + Rcpp::function("clear_data_log", clear_data_log); + Rcpp::function("clear_population_log", clear_population_log); + Rcpp::function("clear_model_log", clear_model_log); + Rcpp::function("clear_recruitment_log", clear_recruitment_log); + Rcpp::function("clear_fleet_log", clear_fleet_log); + Rcpp::function("clear_growth_log", clear_growth_log); + Rcpp::function("clear_maturity_log", clear_maturity_log); + Rcpp::function("clear_selectivity_log", clear_selectivity_log); + Rcpp::function("clear_debug_log", clear_debug_log); + Rcpp::function("get_log", get_log); + Rcpp::function("get_log_errors", get_log_errors); + Rcpp::function("get_log_warnings", get_log_warnings); + Rcpp::function("get_log_info", get_log_info); + Rcpp::function("get_log_module", get_log_module); + Rcpp::function("write_log", write_log); + Rcpp::function("set_log_path", set_log_path); + Rcpp::function("init_logging", init_logging); + Rcpp::function("set_log_throw_on_error", set_log_throw_on_error); + Rcpp::function("log_info", log_info); + Rcpp::function("log_warning", log_warning); + Rcpp::function("log_error", log_error); + Rcpp::class_("Parameter", "FIMS Parameter Class") + .constructor() + .constructor() + .constructor() + .field("value", &Parameter::value_m, "numeric parameter value") + .field("min", &Parameter::min_m, "minimum parameter value") + .field("max", &Parameter::max_m, "maximum parameter value") + .field("id", &Parameter::id_m, "unique id for parameter class") + .field("is_random_effect", &Parameter::is_random_effect_m, "boolean indicating whether or not parameter is a random effect; default value is FALSE") + .field("estimated", &Parameter::estimated_m, "boolean indicating whether or not parameter is estimated; default value is FALSE"); + + Rcpp::class_("ParameterVector") + .constructor() + .constructor() + .constructor() + .field("data", &ParameterVector::storage_m, "list where each element is a Parameter class") + .method("at", &ParameterVector::at, "returns a Parameter at the indicated position given the index argument") + .method("size", &ParameterVector::size, "returns the size of the Parameter Vector") + .method("resize", &ParameterVector::resize, "resizes the Parameter Vector given the provided length argument") + .method("set_all_estimable", &ParameterVector::set_all_estimable, "sets all Parameters within vector as estimable") + .method("set_all_random", &ParameterVector::set_all_random, "sets all Parameters within vector as estimable") + .method("fill", &ParameterVector::fill, "sets the value of all Parameters in the vector with the provided value") + .method("get_id", &ParameterVector::get_id, "get the ID of the interface base object."); + + Rcpp::class_("BevertonHoltRecruitment") + .constructor() + .field("logit_steep", &BevertonHoltRecruitmentInterface::logit_steep) + .field("log_rzero", &BevertonHoltRecruitmentInterface::log_rzero) + .field("log_devs", &BevertonHoltRecruitmentInterface::log_devs) + .field("estimate_log_devs", + &BevertonHoltRecruitmentInterface::estimate_log_devs) + .method("get_id", &BevertonHoltRecruitmentInterface::get_id) + .field("log_sigma_recruit", + &BevertonHoltRecruitmentInterface::log_sigma_recruit) + .method("evaluate", &BevertonHoltRecruitmentInterface::evaluate); + + Rcpp::class_("Fleet") + .constructor() + .field("is_survey", &FleetInterface::is_survey) + .field("log_q", &FleetInterface::log_q) + .field("log_Fmort", &FleetInterface::log_Fmort) + .field("nages", &FleetInterface::nages) + .field("nyears", &FleetInterface::nyears) + .field("estimate_q", &FleetInterface::estimate_q) + .field("random_q", &FleetInterface::random_q) + .field("log_expected_index", &FleetInterface::log_expected_index) + .field("proportion_catch_numbers_at_age", &FleetInterface::proportion_catch_numbers_at_age) + .method("SetSelectivity", &FleetInterface::SetSelectivity); + + Rcpp::class_("AgeComp") + .constructor() + .field("age_comp_data", &AgeCompDataInterface::age_comp_data) + .method("get_id", &AgeCompDataInterface::get_id); + + Rcpp::class_("Index") + .constructor() + .field("index_data", &IndexDataInterface::index_data) + .method("get_id", &IndexDataInterface::get_id); + + Rcpp::class_("Population") + .constructor() + .method("get_id", &PopulationInterface::get_id) + .field("nages", &PopulationInterface::nages) + .field("nfleets", &PopulationInterface::nfleets) + .field("nseasons", &PopulationInterface::nseasons) + .field("nyears", &PopulationInterface::nyears) + .field("log_M", &PopulationInterface::log_M) + .field("log_init_naa", &PopulationInterface::log_init_naa) + .field("proportion_female", &PopulationInterface::proportion_female) + .field("ages", &PopulationInterface::ages) + .field("estimate_prop_female", &PopulationInterface::estimate_prop_female) + .method("evaluate", &PopulationInterface::evaluate) + .method("SetMaturity", &PopulationInterface::SetMaturity) + .method("SetGrowth", &PopulationInterface::SetGrowth) + .method("SetRecruitment", &PopulationInterface::SetRecruitment) + .method("evaluate", &PopulationInterface::evaluate); + + Rcpp::class_("TMBDnormDistribution") + .constructor() + .method("get_id", &DnormDistributionsInterface::get_id) + .method("evaluate", &DnormDistributionsInterface::evaluate) + .method("set_observed_data", &DnormDistributionsInterface::set_observed_data) + .method("set_distribution_links", &DnormDistributionsInterface::set_distribution_links) + .field("x", &DnormDistributionsInterface::x) + .field("expected_values", &DnormDistributionsInterface::expected_values) + .field("log_sd", &DnormDistributionsInterface::log_sd); + + Rcpp::class_("LogisticMaturity") + .constructor() + .field("inflection_point", &LogisticMaturityInterface::inflection_point) + .field("slope", &LogisticMaturityInterface::slope) + .method("get_id", &LogisticMaturityInterface::get_id) + .method("evaluate", &LogisticMaturityInterface::evaluate); + + Rcpp::class_("LogisticSelectivity") + .constructor() + .field("inflection_point", + &LogisticSelectivityInterface::inflection_point) + .field("slope", &LogisticSelectivityInterface::slope) + .method("get_id", &LogisticSelectivityInterface::get_id) + .method("evaluate", &LogisticSelectivityInterface::evaluate); + + Rcpp::class_("DoubleLogisticSelectivity") + .constructor() + .field("inflection_point_asc", + &DoubleLogisticSelectivityInterface::inflection_point_asc) + .field("slope_asc", &DoubleLogisticSelectivityInterface::slope_asc) + .field("inflection_point_desc", + &DoubleLogisticSelectivityInterface::inflection_point_desc) + .field("slope_desc", &DoubleLogisticSelectivityInterface::slope_desc) + .method("get_id", &DoubleLogisticSelectivityInterface::get_id) + .method("evaluate", &DoubleLogisticSelectivityInterface::evaluate); + + Rcpp::class_("EWAAgrowth") + .constructor() + .field("ages", &EWAAGrowthInterface::ages) + .field("weights", &EWAAGrowthInterface::weights) + .method("get_id", &EWAAGrowthInterface::get_id) + .method("evaluate", &EWAAGrowthInterface::evaluate); + + Rcpp::class_("TMBDlnormDistribution") + .constructor() + .method("get_id", &DlnormDistributionsInterface::get_id) + .method("evaluate", &DlnormDistributionsInterface::evaluate) + .method("set_observed_data", &DlnormDistributionsInterface::set_observed_data) + .method("set_distribution_links", &DlnormDistributionsInterface::set_distribution_links) + .field("input_type", &DlnormDistributionsInterface::input_type) + .field("x", &DlnormDistributionsInterface::x) + .field("expected_values", &DlnormDistributionsInterface::expected_values) + .field("log_logsd", &DlnormDistributionsInterface::log_logsd); + + Rcpp::class_("TMBDmultinomDistribution") + .constructor() + .method("evaluate", &DmultinomDistributionsInterface::evaluate) + .method("get_id", &DmultinomDistributionsInterface::get_id) + .method("set_observed_data", &DmultinomDistributionsInterface::set_observed_data) + .method("set_distribution_links", &DmultinomDistributionsInterface::set_distribution_links) + .field("x", &DmultinomDistributionsInterface::x) + .field("expected_values", &DmultinomDistributionsInterface::expected_values) + .field("dims", &DmultinomDistributionsInterface::dims); } #endif /* RCPP_INTERFACE_HPP */ diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_data.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_data.hpp index 3f25e3f7e..fa870ff61 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_data.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_data.hpp @@ -80,6 +80,26 @@ class AgeCompDataInterface : public DataInterfaceBase { /** @brief get the ID of the interface base object */ virtual uint32_t get_id() { return this->id; } + + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\": \"data\",\n"; + ss << " \"type\" : \"AgeComp\",\n"; + ss << " \"id\":" << this->id << ",\n"; + ss << " \"rank\": " << 2 << ",\n"; + ss << " \"dimensions\": [" << this->ymax << "," << this->amax << "],\n"; + ss << " \"values\": ["; + for (size_t i = 0; i < age_comp_data.size() - 1; i++) { + ss << age_comp_data[i] << ", "; + } + ss << age_comp_data[age_comp_data.size() - 1] << "]\n"; + ss << "}"; + return ss.str(); + } + #ifdef TMB_MODEL @@ -143,6 +163,25 @@ class IndexDataInterface : public DataInterfaceBase { /** @brief get the ID of the interface base object */ virtual uint32_t get_id() { return this->id; } + + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\": \"data\",\n"; + ss << " \"type\": \"Index\",\n"; + ss << " \"id\": " << this->id << ",\n"; + ss << " \"rank\": " << 1 << ",\n"; + ss << " \"dimensions\": [" << this->ymax << "],\n"; + ss << " \"values\": ["; + for (size_t i = 0; i < index_data.size() - 1; i++) { + ss << index_data[i] << ", "; + } + ss << index_data[index_data.size() - 1] << "]\n"; + ss << "}"; + return ss.str(); + } #ifdef TMB_MODEL diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_fleet.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_fleet.hpp index b5dc3600f..5f2dd9228 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_fleet.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_fleet.hpp @@ -65,6 +65,13 @@ class FleetInterface : public FleetInterfaceBase { bool estimate_q = false; /**< whether the parameter q should be estimated*/ bool random_q = false; /**< whether q should be a random effect*/ + +Rcpp::NumericVector derived_cnaa; /**< derived quantity: catch numbers at age */ +Rcpp::NumericVector derived_cwaa; /**< derived quantity: catch weight at age */ +Rcpp::NumericVector derived_index; /**< derived quantity: expected index */ +Rcpp::NumericVector derived_age_composition; /**< derived quantity: expected catch */ + + FleetInterface() : FleetInterfaceBase() {} virtual ~FleetInterface() {} diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_growth.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_growth.hpp index 8b60a2c4e..ea98e36af 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_growth.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_growth.hpp @@ -108,6 +108,32 @@ vectors have been set */ EWAAGrowth.ewaa = this->ewaa; return EWAAGrowth.evaluate(age); } + + + virtual std::string to_json() { + std::stringstream ss; + ss << "\"module\" : {\n"; + ss << " \"name\": \"growth\",\n"; + ss << " \"type\" : \"EWAA\",\n"; + ss << " \"id\":" << this->id << ",\n"; + ss << " \"rank\": " << 1 << ",\n"; + ss << " \"dimensions\": [" << this->weights.size() << "],\n"; + + ss << " \"ages\": ["; + for (size_t i = 0; i < ages.size() - 1; i++) { + ss << ages[i] << ", "; + } + ss << ages[ages.size() - 1] << "],\n"; + + ss << " \"values\": ["; + for (size_t i = 0; i < weights.size() - 1; i++) { + ss << weights[i] << ", "; + } + ss << weights[weights.size() - 1] << "]\n"; + ss << "}"; + return ss.str(); + } + #ifdef TMB_MODEL template 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..192c11a9f 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp @@ -24,121 +24,138 @@ * the interface between R and C++ for parameter types. */ class Parameter { - public: - static uint32_t id_g; /**< global id of the 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 + 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) {} - - /** - * @brief Constructor for initializing Parameter. - * @details Inputs include value. - */ - 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++;} + 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) { + } + + /** + * @brief Constructor for initializing Parameter. + * @details Inputs include value. + */ + 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++; + } }; uint32_t Parameter::id_g = 0; +std::ostream& operator<<(std::ostream& out, const Parameter& p) { + out << "Parameter:{" << "id:" << p.id_m << ",value:" << p.value_m << ",min:" << p.min_m << ",max:" << p.max_m << ",estimated:" << p.estimated_m << "}"; + return out; +} /** * @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*/ + 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)); } + /** * @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)); } } + /** * @brief vector constructor * @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)); } } + + ParameterVector(const fims::Vector& v){ + this->id_m = ParameterVector::id_g++; + for (size_t i = 0; i < v.size(); i++) { + Parameter p = v[i]; + this->storage_m.push_back(Rcpp::wrap(p)); + } + } /** * @brief get the ID of the interface base object */ - virtual uint32_t get_id() { return this->id_m; } + virtual uint32_t get_id() { + return this->id_m; + } /** * @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]; } + 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,20 +163,20 @@ 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 +189,8 @@ 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 +202,8 @@ 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 +215,8 @@ 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 +228,8 @@ 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,8 +241,8 @@ 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); @@ -235,23 +252,43 @@ class ParameterVector{ }; uint32_t ParameterVector::id_g = 0; +std::ostream& operator<<(std::ostream& out, ParameterVector& v) { + out<<"ParameterVector:{"; + size_t size = v.size(); + for(size_t i = 0; i < size-1; i++){ + out< 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; - } +public: + + bool finalized = false; + + /**< 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; + } + + virtual void finalize() { + + } + + virtual std::string to_json() { + return ""; + } }; std::vector - FIMSRcppInterfaceBase::fims_interface_objects; +FIMSRcppInterfaceBase::fims_interface_objects; #endif diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_maturity.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_maturity.hpp index a845f33b2..26dd09fad 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_maturity.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_maturity.hpp @@ -22,33 +22,34 @@ * define different Rcpp interfaces for each possible maturity function */ class MaturityInterfaceBase : 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 - live_objects; /**< map associating the ids of +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 + live_objects; /**< map associating the ids of MaturityInterfaceBase to the objects */ - MaturityInterfaceBase() { - this->id = MaturityInterfaceBase::id_g++; - /* Create instance of map: key is id and value is pointer to - MaturityInterfaceBase */ - MaturityInterfaceBase::live_objects[this->id] = this; - FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); - } - - virtual ~MaturityInterfaceBase() {} - - /** @brief get the ID of the interface base object - */ - virtual uint32_t get_id() = 0; - - /** - * @brief evaluate the function - * - */ - virtual double evaluate(double x) = 0; + MaturityInterfaceBase() { + this->id = MaturityInterfaceBase::id_g++; + /* Create instance of map: key is id and value is pointer to + MaturityInterfaceBase */ + MaturityInterfaceBase::live_objects[this->id] = this; + FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); + } + + virtual ~MaturityInterfaceBase() { + } + + /** @brief get the ID of the interface base object + */ + virtual uint32_t get_id() = 0; + + /** + * @brief evaluate the function + * + */ + virtual double evaluate(double x) = 0; }; uint32_t MaturityInterfaceBase::id_g = 1; @@ -59,80 +60,118 @@ std::map MaturityInterfaceBase::live_objects; * instantiate from R: logistic_maturity <- new(logistic_maturity) */ class LogisticMaturityInterface : public MaturityInterfaceBase { - public: - Parameter - inflection_point; /**< the index value at which the response reaches .5 */ - Parameter slope; /**< the width of the curve at the inflection_point */ - - LogisticMaturityInterface() : MaturityInterfaceBase() {} - - virtual ~LogisticMaturityInterface() {} - - /** @brief returns the id for the logistic maturity interface */ - virtual uint32_t get_id() { return this->id; } - - /** @brief evaluate the logistic maturity function - * @param x The independent variable in the logistic function (e.g., age or - * size in maturity). - */ - virtual double evaluate(double x) { - fims_popdy::LogisticMaturity LogisticMat; - LogisticMat.inflection_point.resize(1); - LogisticMat.inflection_point[0] = this->inflection_point.value_m; - LogisticMat.slope.resize(1); - LogisticMat.slope[0] = this->slope.value_m; - return LogisticMat.evaluate(x); - } +public: + Parameter + inflection_point; /**< the index value at which the response reaches .5 */ + Parameter slope; /**< the width of the curve at the inflection_point */ -#ifdef TMB_MODEL + double estimated_inflection_point; /**< estimmated result of the index value at which the response reaches .5 */ + double estimated_slope; /**< estimmated result of the width of the curve at the inflection_point */ + + LogisticMaturityInterface() : MaturityInterfaceBase() { + } - template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = - fims_info::Information::GetInstance(); - - std::shared_ptr > maturity = - std::make_shared >(); - - // set relative info - maturity->id = this->id; - maturity->inflection_point.resize(1); - maturity->inflection_point[0] = this->inflection_point.value_m; - if (this->inflection_point.estimated_m) { - info->RegisterParameterName("maturity inflection_point"); - if (this->inflection_point.is_random_effect_m) { - info->RegisterRandomEffect(maturity->inflection_point[0]); - } else { - info->RegisterParameter(maturity->inflection_point[0]); - } + virtual ~LogisticMaturityInterface() { } - maturity->slope.resize(1); - maturity->slope[0] = this->slope.value_m; - if (this->slope.estimated_m) { - info->RegisterParameterName("maturity slope"); - if (this->slope.is_random_effect_m) { - info->RegisterRandomEffect(maturity->slope[0]); - } else { - info->RegisterParameter(maturity->slope[0]); - } + + /** @brief returns the id for the logistic maturity interface */ + virtual uint32_t get_id() { + return this->id; + } + + /** @brief evaluate the logistic maturity function + * @param x The independent variable in the logistic function (e.g., age or + * size in maturity). + */ + virtual double evaluate(double x) { + fims_popdy::LogisticMaturity LogisticMat; + LogisticMat.inflection_point.resize(1); + LogisticMat.inflection_point[0] = this->inflection_point.value_m; + LogisticMat.slope.resize(1); + LogisticMat.slope[0] = this->slope.value_m; + return LogisticMat.evaluate(x); + } + + virtual std::string to_json() { + std::stringstream ss; + ss << "\"module\" : {\n"; + ss << " \"name\": \"maturity\",\n"; + ss << " \"type\": \"Logistic\",\n"; + ss << " \"id\": " << this->id << ",\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"inflection_point\",\n"; + ss << " \"id\":" << this->inflection_point.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->inflection_point.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_inflection_point << ",\n"; + ss << " \"is_estimated\":" << this->inflection_point.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->inflection_point.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"slope\",\n"; + ss << " \"id\":" << this->slope.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->slope.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_slope << ",\n"; + ss << " \"is_estimated\":" << this->slope.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->slope.is_random_effect_m << "\n }\n"; + + + ss << "}"; + + return ss.str(); } - // add to Information - info->maturity_models[maturity->id] = maturity; +#ifdef TMB_MODEL - return true; - } + template + bool add_to_fims_tmb_internal() { + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + std::shared_ptr > maturity = + std::make_shared >(); + + // set relative info + maturity->id = this->id; + maturity->inflection_point.resize(1); + maturity->inflection_point[0] = this->inflection_point.value_m; + if (this->inflection_point.estimated_m) { + info->RegisterParameterName("maturity inflection_point"); + if (this->inflection_point.is_random_effect_m) { + info->RegisterRandomEffect(maturity->inflection_point[0]); + } else { + info->RegisterParameter(maturity->inflection_point[0]); + } + } + maturity->slope.resize(1); + maturity->slope[0] = this->slope.value_m; + if (this->slope.estimated_m) { + info->RegisterParameterName("maturity slope"); + if (this->slope.is_random_effect_m) { + info->RegisterRandomEffect(maturity->slope[0]); + } else { + info->RegisterParameter(maturity->slope[0]); + } + } + + // add to Information + info->maturity_models[maturity->id] = maturity; + + return true; + } - /** @brief this adds the parameter values and derivatives to the TMB model - * object */ - virtual bool add_to_fims_tmb() { - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); + /** @brief this adds the parameter values and derivatives to the TMB model + * object */ + virtual bool add_to_fims_tmb() { + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); - return true; - } + return true; + } #endif }; diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_population.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_population.hpp index 07885098d..144e72ace 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_population.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_population.hpp @@ -20,31 +20,32 @@ * define different Rcpp interfaces for each possible Population function */ class PopulationInterfaceBase : public FIMSRcppInterfaceBase { - public: - static uint32_t id_g; /**< static id of the population interface base*/ - uint32_t id; /**< id of the population interface base */ - // live objects in C++ are objects that have been created and live in memory - static std::map - live_objects; /**< map associating the ids of PopulationInterfaceBase to +public: + static uint32_t id_g; /**< static id of the population interface base*/ + uint32_t id; /**< id of the population interface base */ + // live objects in C++ are objects that have been created and live in memory + static std::map + live_objects; /**< map associating the ids of PopulationInterfaceBase to the objects */ - PopulationInterfaceBase() { - this->id = PopulationInterfaceBase::id_g++; - /* Create instance of map: key is id and value is pointer to - PopulationInterfaceBase */ - PopulationInterfaceBase::live_objects[this->id] = this; - PopulationInterfaceBase::fims_interface_objects.push_back(this); - } + PopulationInterfaceBase() { + this->id = PopulationInterfaceBase::id_g++; + /* Create instance of map: key is id and value is pointer to + PopulationInterfaceBase */ + PopulationInterfaceBase::live_objects[this->id] = this; + PopulationInterfaceBase::fims_interface_objects.push_back(this); + } - virtual ~PopulationInterfaceBase() {} + virtual ~PopulationInterfaceBase() { + } - /** @brief get_id method for child classes to inherit */ - virtual uint32_t get_id() = 0; + /** @brief get_id method for child classes to inherit */ + virtual uint32_t get_id() = 0; }; uint32_t PopulationInterfaceBase::id_g = 1; std::map - PopulationInterfaceBase::live_objects; +PopulationInterfaceBase::live_objects; /** * @brief Rcpp interface for a new Population. To instantiate @@ -52,130 +53,401 @@ std::map * population <- new(population) */ class PopulationInterface : public PopulationInterfaceBase { - public: - uint32_t nages; /**< number of ages */ - uint32_t nfleets; /**< number of fleets */ - uint32_t nseasons; /**< number of seasons */ - uint32_t nyears; /**< number of years */ - uint32_t maturity_id; /**< id of the maturity function*/ - uint32_t growth_id; /**< id of the growth function*/ - uint32_t recruitment_id; /**< id of the recruitment function*/ - ParameterVector log_M; /**< log of the natural mortality of the stock*/ - ParameterVector log_init_naa; /**id; } - - /** - * @brief Set the unique id for the Maturity object - * - * @param maturity_id Unique id for the Maturity object - */ - void SetMaturity(uint32_t maturity_id) { this->maturity_id = maturity_id; } - - /** - * @brief Set the unique id for the growth object - * - * @param growth_id Unique id for the growth object - */ - void SetGrowth(uint32_t growth_id) { this->growth_id = growth_id; } - - /** - * @brief Set the unique id for the Maturity object - * - * @param recruitment_id Unique id for the Maturity object - */ - void SetRecruitment(uint32_t recruitment_id) { - this->recruitment_id = recruitment_id; - } - - /** @brief evaluate the population function */ - virtual void evaluate() { - fims_popdy::Population population; - return population.Evaluate(); - } + bool estimate_prop_female; /** - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = - fims_info::Information::GetInstance(); - - std::shared_ptr > population = - std::make_shared >(); - - // set relative info - population->id = this->id; - population->nyears = this->nyears; - population->nfleets = this->nfleets; - population->nseasons = this->nseasons; - population->nages = this->nages; - if (this->nages == this->ages.size()) { - population->ages.resize(this->nages); - } else { - warning("The ages vector is not of size nages."); + + Rcpp::NumericVector derived_ssb; /**< derived quantity: spawning stock biomass */ + Rcpp::NumericVector derived_naa; /**< derived quantity: numbers at age */ + Rcpp::NumericVector derived_biomass; /**< derived quantity: biomass */ + Rcpp::NumericVector derived_recruitment; /**< derived quantity: recruitment */ + + Rcpp::NumericVector estimated_log_M; + Rcpp::NumericVector estimated_log_init_naa; + Rcpp::NumericVector estimated_proportion_female; + std::string name; + + PopulationInterface() : PopulationInterfaceBase() { + } + + virtual ~PopulationInterface() { + } + + virtual uint32_t get_id() { + return this->id; } - population->growth_id = this->growth_id; - population->recruitment_id = this->recruitment_id; - population->maturity_id = this->maturity_id; - population->log_M.resize(this->log_M.size()); - population->log_init_naa.resize(this->log_init_naa.size()); - for (size_t i = 0; i < log_M.size(); i++) { - population->log_M[i] = this->log_M[i].value_m; - if (this->log_M[i].estimated_m) { - info->RegisterParameterName("log_M"); - info->RegisterParameter(population->log_M[i]); - } + /** + * @brief Set the unique id for the Maturity object + * + * @param maturity_id Unique id for the Maturity object + */ + void SetMaturity(uint32_t maturity_id) { + this->maturity_id = maturity_id; } - info->variable_map[this->log_M.id_m] = &(population)->log_M; - - for (size_t i = 0; i < log_init_naa.size(); i++) { - population->log_init_naa[i] = this->log_init_naa[i].value_m; - if (this->log_init_naa[i].estimated_m) { - info->RegisterParameterName("log_init_naa"); - info->RegisterParameter(population->log_init_naa[i]); - } + + /** + * @brief Set the unique id for the growth object + * + * @param growth_id Unique id for the growth object + */ + void SetGrowth(uint32_t growth_id) { + this->growth_id = growth_id; } - info->variable_map[this->log_init_naa.id_m] = &(population)->log_init_naa; - for (int i = 0; i < ages.size(); i++) { - population->ages[i] = this->ages[i]; + + /** + * @brief Set the unique id for the Maturity object + * + * @param recruitment_id Unique id for the Maturity object + */ + void SetRecruitment(uint32_t recruitment_id) { + this->recruitment_id = recruitment_id; + } + + /** @brief evaluate the population function */ + virtual void evaluate() { + fims_popdy::Population population; + return population.Evaluate(); + } + + + /** + * @brief finalize function. Extracts derived quantities back to + * the Rcpp interface object from the Information object. + */ + virtual void finalize() { + + if (this->finalized) { + //log warning that finalize has been called more than once. + FIMS_WARNING_LOG("Population " + fims::to_string(this->id) + " has been finalized already."); + } + + this->finalized = true; //indicate this has been called already + + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + + + + this->estimated_log_M = Rcpp::NumericVector(this->log_M.size()); + for (size_t i = 0; i < this->log_M.size(); i++) { + this->estimated_log_M[i] = this->log_M[i].value_m; + } + + this->estimated_log_init_naa = Rcpp::NumericVector(this->log_init_naa.size()); + for (size_t i = 0; i < this->log_init_naa.size(); i++) { + this->estimated_log_init_naa[i] = this->log_init_naa[i].value_m; + } + + this->estimated_proportion_female = Rcpp::NumericVector(this->proportion_female.size()); + for (size_t i = 0; i < this->proportion_female.size(); i++) { + this->estimated_proportion_female[i] = this->proportion_female[i]; + } + + fims_info::Information::population_iterator it; + + + it = info->populations.find(this->id); + + std::shared_ptr > pop = + info->populations[this->id]; + it = info->populations.find(this->id); + if (it == info->populations.end()) { + FIMS_WARNING_LOG("Population " + fims::to_string(this->id) + " not found in Information."); + return; + } else { + + if (this->estimated_log_M) { + for (size_t i = 0; i < this->log_M.size(); i++) { + this->estimated_log_M[i] = pop->log_M[i]; + } + } + + if (this->estimated_log_init_naa) { + for (size_t i = 0; i < this->log_init_naa.size(); i++) { + this->estimated_log_init_naa[i] = pop->log_init_naa[i]; + } + } + + if (this->estimate_prop_female) { + for (size_t i = 0; i < this->proportion_female.size(); i++) { + this->estimated_proportion_female[i] = pop->proportion_female[i]; + } + } + + this->derived_naa = Rcpp::NumericVector(pop->numbers_at_age.size()); + this->derived_ssb = Rcpp::NumericVector(pop->spawning_biomass.size()); + this->derived_biomass = Rcpp::NumericVector(pop->biomass.size()); + this->derived_recruitment = Rcpp::NumericVector(pop->expected_recruitment.size()); + + //set naa from Information/ + for (size_t i = 0; i < this->derived_naa.size(); i++) { + this->derived_naa[i] = pop->numbers_at_age[i]; + } + + //set ssb from Information/ + for (size_t i = 0; i < this->derived_ssb.size(); i++) { + this->derived_ssb[i] = pop->spawning_biomass[i]; + } + + //set biomass from Information + for (size_t i = 0; i < this->derived_biomass.size(); i++) { + this->derived_biomass[i] = pop->biomass[i]; + } + + //set recruitment from Information/ + for (size_t i = 0; i < this->derived_recruitment.size(); i++) { + this->derived_recruitment[i] = pop->expected_recruitment[i]; + } + + } + } - for (int i = 0; i < proportion_female.size(); i++) { - population->proportion_female[i] = this->proportion_female[i]; - if (estimate_prop_female) { - info->RegisterParameter(population->proportion_female[i]); - } + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\" : \"Population\",\n"; + + ss << " \"type\" : \"population\",\n"; + ss << " \"tag\" : \"" << this->name << "\",\n"; + ss << " \"id\": " << this->id << ",\n"; + ss << " \"recruitment_id\": " << this->recruitment_id << ",\n"; + ss << " \"growth_id\": " << this->growth_id << ",\n"; + ss << " \"maturity_id\": " << this->maturity_id << ",\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"log_M\",\n"; + ss << " \"id\":" << -999 << ",\n"; + ss << " \"type\": \"vector\",\n"; + ss << " \"values\":["; + + if (this->log_M.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->log_M.size() - 1; i++) { + ss << this->log_M[i] << ", "; + } + ss << this->log_M[this->log_M.size() - 1] << "],\n"; + } + + ss << " \"estimated_values\":["; + if (this->estimated_log_M.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->estimated_log_M.size() - 1; i++) { + ss << this->estimated_log_M[i] << ", "; + } + ss << this->estimated_log_M[this->estimated_log_M.size() - 1] << "],\n"; + } + + ss << " \"is_estimated\":" << this->estimated_log_M << ",\n"; + ss << " \"is_random_effect\":" << 0 << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"log_init_naa\",\n"; + ss << " \"id\":" << -999 << ",\n"; + ss << " \"type\": \"vector\",\n"; + ss << " \"values\":["; + + if (this->log_init_naa.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->log_init_naa.size() - 1; i++) { + ss << this->log_init_naa[i] << ", "; + } + ss << this->log_init_naa[this->log_init_naa.size() - 1] << "],\n"; + } + + ss << " \"estimated_values\":["; + if (this->estimated_log_init_naa.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->estimated_log_init_naa.size() - 1; i++) { + ss << this->estimated_log_init_naa[i] << ", "; + } + ss << this->estimated_log_init_naa[this->estimated_log_init_naa.size() - 1] << "],\n"; + } + + ss << " \"is_estimated\":" << this->estimated_log_init_naa << ",\n"; + ss << " \"is_random_effect\":" << 0 << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"proportion_female\",\n"; + ss << " \"id\":" << -999 << ",\n"; + ss << " \"type\": \"vector\",\n"; + ss << " \"values\":["; + + if (this->proportion_female.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->proportion_female.size() - 1; i++) { + ss << this->proportion_female[i] << ", "; + } + ss << this->proportion_female[this->proportion_female.size() - 1] << "],\n"; + } + + ss << " \"estimated_values\":["; + if (this->estimated_proportion_female.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->estimated_proportion_female.size() - 1; i++) { + ss << this->estimated_proportion_female[i] << ", "; + } + ss << this->estimated_proportion_female[this->estimated_proportion_female.size() - 1] << "],\n"; + } + + ss << " \"is_estimated\":" << this->estimate_prop_female << ",\n"; + ss << " \"is_random_effect\":" << 0 << "\n},\n"; + + + ss << " \"derived_quantity\": {\n"; + ss << " \"name\": \"ssb\",\n"; + ss << " \"values\":["; + if (this->derived_ssb.size() == 0) { + ss << "]\n"; + } else { + for (size_t i = 0; i < this->derived_ssb.size() - 1; i++) { + ss << this->derived_ssb[i] << ", "; + } + ss << this->derived_ssb[this->derived_ssb.size() - 1] << "]\n"; + } + ss << " },\n"; + + ss << " \"derived_quantity\": {\n"; + ss << " \"name\": \"naa\",\n"; + ss << " \"values\":["; + if (this->derived_naa.size() == 0) { + ss << "]\n"; + } else { + for (size_t i = 0; i < this->derived_naa.size() - 1; i++) { + ss << this->derived_naa[i] << ", "; + } + ss << this->derived_naa[this->derived_naa.size() - 1] << "]\n"; + } + ss << " },\n"; + + ss << " \"derived_quantity\": {\n"; + ss << " \"name\": \"biomass\",\n"; + ss << " \"values\":["; + if (this->derived_biomass.size() == 0) { + ss << "]\n"; + } else { + for (size_t i = 0; i < this->derived_biomass.size() - 1; i++) { + ss << this->derived_biomass[i] << ", "; + } + ss << this->derived_biomass[this->derived_biomass.size() - 1] << "]\n"; + } + ss << " },\n"; + + ss << " \"derived_quantity\": {\n"; + ss << " \"name\": \"recruitment\",\n"; + ss << " \"values\":["; + if (this->derived_recruitment.size() == 0) { + ss << "]\n"; + } else { + for (size_t i = 0; i < this->derived_recruitment.size() - 1; i++) { + ss << this->derived_recruitment[i] << ", "; + } + ss << this->derived_recruitment[this->derived_recruitment.size() - 1] << "]\n"; + } + ss << " }\n"; + + ss << "}"; + + return ss.str(); } - population->numbers_at_age.resize((nyears + 1) * nages); - info->variable_map[this->numbers_at_age.id_m] = &(population)->numbers_at_age; - // add to Information - info->populations[population->id] = population; +#ifdef TMB_MODEL + + template + bool add_to_fims_tmb_internal() { + std::shared_ptr > info = + fims_info::Information::GetInstance(); - return true; - } + std::shared_ptr > population = + std::make_shared >(); - /** @brief this adds the parameter values and derivatives to the TMB model - * object */ - virtual bool add_to_fims_tmb() { - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); + // set relative info + population->id = this->id; + population->nyears = this->nyears; + population->nfleets = this->nfleets; + population->nseasons = this->nseasons; + population->nages = this->nages; + if (this->nages == this->ages.size()) { + population->ages.resize(this->nages); + } else { + warning("The ages vector is not of size nages."); + } - return true; - } + population->growth_id = this->growth_id; + population->recruitment_id = this->recruitment_id; + population->maturity_id = this->maturity_id; + population->log_M.resize(this->log_M.size()); + population->log_init_naa.resize(this->log_init_naa.size()); + for (size_t i = 0; i < log_M.size(); i++) { + population->log_M[i] = this->log_M[i].value_m; + if (this->log_M[i].estimated_m) { + info->RegisterParameterName("log_M"); + info->RegisterParameter(population->log_M[i]); + } + } + info->variable_map[this->log_M.id_m] = &(population)->log_M; + + for (size_t i = 0; i < log_init_naa.size(); i++) { + population->log_init_naa[i] = this->log_init_naa[i].value_m; + if (this->log_init_naa[i].estimated_m) { + info->RegisterParameterName("log_init_naa"); + info->RegisterParameter(population->log_init_naa[i]); + } + } + info->variable_map[this->log_init_naa.id_m] = &(population)->log_init_naa; + for (int i = 0; i < ages.size(); i++) { + population->ages[i] = this->ages[i]; + } + for (int i = 0; i < proportion_female.size(); i++) { + population->proportion_female[i] = this->proportion_female[i]; + if (estimate_prop_female) { + info->RegisterParameter(population->proportion_female[i]); + } + } + + population->numbers_at_age.resize((nyears + 1) * nages); + info->variable_map[this->numbers_at_age.id_m] = &(population)->numbers_at_age; + + // add to Information + info->populations[population->id] = population; + + return true; + } + + /** @brief this adds the parameter values and derivatives to the TMB model + * object */ + virtual bool add_to_fims_tmb() { + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + + return true; + } #endif }; diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_recruitment.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_recruitment.hpp index 733f8a74e..78a07599d 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_recruitment.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_recruitment.hpp @@ -21,41 +21,42 @@ * define different Rcpp interfaces for each possible Recruitment function */ class RecruitmentInterfaceBase : 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 live_objects; - /**< map associating the ids of RecruitmentInterfaceBase to the objects */ - - // static std::vector log_recruit_devs; /**< vector of log recruitment - // deviations*/ - // static bool constrain_deviations; /**< whether or not the rec devs are - // constrained*/ - - RecruitmentInterfaceBase() { - this->id = RecruitmentInterfaceBase::id_g++; - /* Create instance of map: key is id and value is pointer to - RecruitmentInterfaceBase */ - RecruitmentInterfaceBase::live_objects[this->id] = this; - FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); - } - - virtual ~RecruitmentInterfaceBase() {} - - /** @brief get the ID of the interface base object - */ - virtual uint32_t get_id() = 0; - - /** @brief evaluate method for child recruitment interface objects to inherit - */ - virtual double evaluate(double spawners, double ssbzero) = 0; +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 live_objects; + /**< map associating the ids of RecruitmentInterfaceBase to the objects */ + + // static std::vector log_recruit_devs; /**< vector of log recruitment + // deviations*/ + // static bool constrain_deviations; /**< whether or not the rec devs are + // constrained*/ + + RecruitmentInterfaceBase() { + this->id = RecruitmentInterfaceBase::id_g++; + /* Create instance of map: key is id and value is pointer to + RecruitmentInterfaceBase */ + RecruitmentInterfaceBase::live_objects[this->id] = this; + FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); + } + + virtual ~RecruitmentInterfaceBase() { + } + + /** @brief get the ID of the interface base object + */ + virtual uint32_t get_id() = 0; + + /** @brief evaluate method for child recruitment interface objects to inherit + */ + virtual double evaluate(double spawners, double ssbzero) = 0; }; uint32_t RecruitmentInterfaceBase::id_g = 1; std::map - RecruitmentInterfaceBase::live_objects; +RecruitmentInterfaceBase::live_objects; /** * @brief Rcpp interface for Beverton-Holt as an S4 object. To instantiate @@ -63,115 +64,250 @@ std::map * beverton_holt <- new(beverton_holt) */ class BevertonHoltRecruitmentInterface : public RecruitmentInterfaceBase { - public: - Parameter logit_steep; /**< steepness or the productivity of the stock*/ - Parameter log_rzero; /**< recruitment at unfished biomass */ - Parameter - log_sigma_recruit; /**< the log of the stock recruit standard deviation */ - ParameterVector log_devs; /**< log recruitment deviations*/ - bool estimate_log_devs = false; /**< boolean describing whether to estimate */ - - BevertonHoltRecruitmentInterface() : RecruitmentInterfaceBase() {} - - virtual ~BevertonHoltRecruitmentInterface() {} - - virtual uint32_t get_id() { return this->id; } - - virtual double evaluate(double spawners, double ssbzero) { - fims_popdy::SRBevertonHolt BevHolt; - BevHolt.logit_steep.resize(1); - BevHolt.logit_steep[0] = this->logit_steep.value_m; - if (this->logit_steep.value_m == 1.0) { - warning( - "Steepness is subject to a logit transformation, so its value is " - "0.7848469. Fixing it at 1.0 is not currently possible."); - } - BevHolt.log_rzero.resize(1); - BevHolt.log_rzero[0] = this->log_rzero.value_m; +public: + Parameter logit_steep; /**< steepness or the productivity of the stock*/ + Parameter log_rzero; /**< recruitment at unfished biomass */ + Parameter + log_sigma_recruit; /**< the log of the stock recruit standard deviation */ + ParameterVector log_devs; /**< log recruitment deviations*/ + bool estimate_log_devs = false; /**< boolean describing whether to estimate */ - return BevHolt.evaluate(spawners, ssbzero); - } + double estimated_logit_steep; /**< estimated steepness or the productivity of the stock*/ + double estimated_log_rzero; /**< estimated recruitment at unfished biomass */ + double estimated_log_sigma_recruit; /**< estimated log of the stock recruit standard deviation */ + Rcpp::NumericVector estimated_log_devs; /**< estimated log recruitment deviations*/ + BevertonHoltRecruitmentInterface() : RecruitmentInterfaceBase() { + } -#ifdef TMB_MODEL + virtual ~BevertonHoltRecruitmentInterface() { + } - template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = - fims_info::Information::GetInstance(); - - std::shared_ptr > recruitment = - std::make_shared >(); - - // set relative info - recruitment->id = this->id; - //set logit_steep - recruitment->logit_steep.resize(1); - recruitment->logit_steep[0] = this->logit_steep.value_m; - if (this->logit_steep.estimated_m) { - info->RegisterParameterName("logit_steep"); - if (this->logit_steep.is_random_effect_m) { - info->RegisterRandomEffect(recruitment->logit_steep[0]); - } else { - info->RegisterParameter(recruitment->logit_steep[0]); - } + virtual uint32_t get_id() { + return this->id; } - info->variable_map[this->logit_steep.id_m] = &(recruitment)->logit_steep; - - //set log_rzero - recruitment->log_rzero.resize(1); - recruitment->log_rzero[0] = this->log_rzero.value_m; - if (this->log_rzero.estimated_m) { - info->RegisterParameterName("log_rzero"); - if (this->log_rzero.is_random_effect_m) { - info->RegisterRandomEffect(recruitment->log_rzero[0]); - } else { - info->RegisterParameter(recruitment->log_rzero[0]); - } + + virtual double evaluate(double spawners, double ssbzero) { + fims_popdy::SRBevertonHolt BevHolt; + BevHolt.logit_steep.resize(1); + BevHolt.logit_steep[0] = this->logit_steep.value_m; + if (this->logit_steep.value_m == 1.0) { + warning( + "Steepness is subject to a logit transformation, so its value is " + "0.7848469. Fixing it at 1.0 is not currently possible."); + } + BevHolt.log_rzero.resize(1); + BevHolt.log_rzero[0] = this->log_rzero.value_m; + + return BevHolt.evaluate(spawners, ssbzero); } - info->variable_map[this->log_rzero.id_m] = &(recruitment)->log_rzero; - - //set log_sigma_recruit - recruitment->log_sigma_recruit.resize(1); - recruitment->log_sigma_recruit[0] = this->log_sigma_recruit.value_m; - if (this->log_sigma_recruit.estimated_m) { - info->RegisterParameterName("log_sigma_recruit"); - if (this->log_sigma_recruit.is_random_effect_m) { - info->RegisterRandomEffect(recruitment->log_sigma_recruit[0]); - } else { - info->RegisterParameter(recruitment->log_sigma_recruit[0]); - } + + virtual void finalize() { + + if (this->finalized) { + //log warning that finalize has been called more than once. + FIMS_WARNING_LOG("Beverton-Holt Recruitment " + fims::to_string(this->id) + " has been finalized already."); + } + + this->finalized = true; //indicate this has been called already + + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + + this->estimated_logit_steep = this->logit_steep.value_m; + this->estimated_log_rzero = this->log_rzero.value_m; + this->estimated_log_sigma_recruit = this->log_sigma_recruit.value_m; + + this->estimated_log_devs = Rcpp::NumericVector(this->log_devs.size()); + + for (size_t i = 0; i < this->estimated_log_devs.size(); i++) { + this->estimated_log_devs[i] = log_devs[i].value_m; + } + + fims_info::Information::recruitment_models_iterator it; + + it = info->recruitment_models.find(this->id); + + if (it == info->recruitment_models.end()) { + FIMS_WARNING_LOG("Beverton-Holt Recruitment " + fims::to_string(this->id) + " not found in Information."); + return; + } else { + + std::shared_ptr > recr = + std::dynamic_pointer_cast >(it->second); + + if (this->logit_steep.estimated_m) { + this->estimated_logit_steep = recr->logit_steep[0]; + } + + if (log_rzero.estimated_m) { + this->estimated_log_rzero = recr->log_rzero[0]; + } + + if (log_sigma_recruit.estimated_m) { + this->estimated_log_sigma_recruit = recr->log_sigma_recruit[0]; + } + + + if (this->estimate_log_devs) { + for (size_t i = 0; i < this->estimated_log_devs.size(); i++) { + this->estimated_log_devs[i] = recr->log_recruit_devs[i]; + } + } + } + + } - info->variable_map[this->log_sigma_recruit.id_m] = &(recruitment)->log_sigma_recruit; - - //set log_recruit_devs - recruitment->log_recruit_devs.resize(this->log_devs.size()); - for (size_t i = 0; i < recruitment->log_recruit_devs.size(); i++) { - recruitment->log_recruit_devs[i] = this->log_devs[i].value_m; - if (this->estimate_log_devs) { - info->RegisterParameter(recruitment->log_recruit_devs[i]); - } else { - recruitment->estimate_log_recruit_devs = false; - } + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\": \"recruitment\",\n"; + ss << " \"type\": \"Beverton-Holt\",\n"; + ss << " \"id\": " << this->id << ",\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"logit_steep\",\n"; + ss << " \"id\":" << this->logit_steep.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->logit_steep.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_logit_steep << ",\n"; + ss << " \"is_estimated\":" << this->logit_steep.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->logit_steep.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"log_rzero\",\n"; + ss << " \"id\":" << this->log_rzero.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->log_rzero.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_log_rzero << ",\n"; + ss << " \"is_estimated\":" << this->log_rzero.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->log_rzero.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"log_sigma_recruit\",\n"; + ss << " \"id\":" << this->log_sigma_recruit.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->log_sigma_recruit.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_log_sigma_recruit << ",\n"; + ss << " \"is_estimated\":" << this->log_sigma_recruit.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->log_sigma_recruit.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"log_devs\",\n"; + ss << " \"id\":" << -999 << ",\n"; + ss << " \"type\": \"vector\",\n"; + ss << " \"values\":["; + + if (this->log_devs.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->log_devs.size() - 1; i++) { + ss << this->log_devs[i] << ", "; + } + ss << this->log_devs[this->log_devs.size() - 1] << "],\n"; + } + + ss << " \"estimated_values\":["; + if (this->estimated_log_devs.size() == 0) { + ss << "],\n"; + } else { + for (size_t i = 0; i < this->estimated_log_devs.size() - 1; i++) { + ss << this->estimated_log_devs[i] << ", "; + } + ss << this->estimated_log_devs[this->estimated_log_devs.size() - 1] << "],\n"; + } + + ss << " \"is_estimated\":" << this->estimate_log_devs << ",\n"; + ss << " \"is_random_effect\":" << 0 << "\n }\n"; + + + ss << "}"; + + return ss.str(); } - info->variable_map[this->log_devs.id_m] = &(recruitment)->log_recruit_devs; - // add to Information - info->recruitment_models[recruitment->id] = recruitment; +#ifdef TMB_MODEL + + template + bool add_to_fims_tmb_internal() { + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + std::shared_ptr > recruitment = + std::make_shared >(); + + // set relative info + recruitment->id = this->id; + //set logit_steep + recruitment->logit_steep.resize(1); + recruitment->logit_steep[0] = this->logit_steep.value_m; + if (this->logit_steep.estimated_m) { + info->RegisterParameterName("logit_steep"); + if (this->logit_steep.is_random_effect_m) { + info->RegisterRandomEffect(recruitment->logit_steep[0]); + } else { + info->RegisterParameter(recruitment->logit_steep[0]); + } + } + info->variable_map[this->logit_steep.id_m] = &(recruitment)->logit_steep; - return true; - } + //set log_rzero + recruitment->log_rzero.resize(1); + recruitment->log_rzero[0] = this->log_rzero.value_m; + if (this->log_rzero.estimated_m) { + info->RegisterParameterName("log_rzero"); + if (this->log_rzero.is_random_effect_m) { + info->RegisterRandomEffect(recruitment->log_rzero[0]); + } else { + info->RegisterParameter(recruitment->log_rzero[0]); + } + } + info->variable_map[this->log_rzero.id_m] = &(recruitment)->log_rzero; - /** @brief this adds the parameter values and derivatives to the TMB model - * object */ - virtual bool add_to_fims_tmb() { - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); + //set log_sigma_recruit + recruitment->log_sigma_recruit.resize(1); + recruitment->log_sigma_recruit[0] = this->log_sigma_recruit.value_m; + if (this->log_sigma_recruit.estimated_m) { + info->RegisterParameterName("log_sigma_recruit"); + if (this->log_sigma_recruit.is_random_effect_m) { + info->RegisterRandomEffect(recruitment->log_sigma_recruit[0]); + } else { + info->RegisterParameter(recruitment->log_sigma_recruit[0]); + } + } + info->variable_map[this->log_sigma_recruit.id_m] = &(recruitment)->log_sigma_recruit; - return true; - } + //set log_recruit_devs + recruitment->log_recruit_devs.resize(this->log_devs.size()); + for (size_t i = 0; i < recruitment->log_recruit_devs.size(); i++) { + recruitment->log_recruit_devs[i] = this->log_devs[i].value_m; + if (this->estimate_log_devs) { + info->RegisterParameter(recruitment->log_recruit_devs[i]); + } else { + recruitment->estimate_log_recruit_devs = false; + } + } + info->variable_map[this->log_devs.id_m] = &(recruitment)->log_recruit_devs; + + // add to Information + info->recruitment_models[recruitment->id] = recruitment; + + return true; + } + + /** @brief this adds the parameter values and derivatives to the TMB model + * object */ + virtual bool add_to_fims_tmb() { + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + + return true; + } #endif }; diff --git a/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp b/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp index 9e5e08094..c314c9666 100644 --- a/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp +++ b/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp @@ -21,120 +21,201 @@ * define different Rcpp interfaces for each possible Selectivity function */ 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 - live_objects; /**< map associating the ids of +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 + live_objects; /**< map associating the ids of SelectivityInterfaceBase to the objects */ - SelectivityInterfaceBase() { - this->id = SelectivityInterfaceBase::id_g++; - /* Create instance of map: key is id and value is pointer to - SelectivityInterfaceBase */ - SelectivityInterfaceBase::live_objects[this->id] = this; - FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); - } - - virtual ~SelectivityInterfaceBase() {} - - /** @brief get the ID of the interface base object - */ - virtual uint32_t get_id() = 0; - - /** - * @brief evaluate the function - * - */ - virtual double evaluate(double x) = 0; + SelectivityInterfaceBase() { + this->id = SelectivityInterfaceBase::id_g++; + /* Create instance of map: key is id and value is pointer to + SelectivityInterfaceBase */ + SelectivityInterfaceBase::live_objects[this->id] = this; + FIMSRcppInterfaceBase::fims_interface_objects.push_back(this); + } + + virtual ~SelectivityInterfaceBase() { + } + + /** @brief get the ID of the interface base object + */ + virtual uint32_t get_id() = 0; + + /** + * @brief evaluate the function + * + */ + virtual double evaluate(double x) = 0; }; uint32_t SelectivityInterfaceBase::id_g = 1; std::map - SelectivityInterfaceBase::live_objects; +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: - 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() {} - - virtual ~LogisticSelectivityInterface() {} - - /** @brief returns the id for the logistic selectivity interface */ - virtual uint32_t get_id() { return this->id; } - - /** @brief evaluate the logistic selectivity function - * @param x The independent variable in the logistic function (e.g., age or - * size in selectivity). - */ - virtual double evaluate(double x) { - fims_popdy::LogisticSelectivity LogisticSel; - LogisticSel.inflection_point.resize(1); - LogisticSel.inflection_point[0] = this->inflection_point.value_m; - LogisticSel.slope.resize(1); - LogisticSel.slope[0] = this->slope.value_m; - return LogisticSel.evaluate(x); - } +public: + Parameter + inflection_point; /**< the index value at which the response reaches .5 */ + Parameter slope; /**< the width of the curve at the inflection_point */ -#ifdef TMB_MODEL + double estimated_inflection_point; /**< estimmated result of the index value at which the response reaches .5 */ + double estimated_slope; /**< estimmated result of the width of the curve at the inflection_point */ - template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = - fims_info::Information::GetInstance(); - - 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) { - info->RegisterParameterName("logistic selectivity inflection_point"); - if (this->inflection_point.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->inflection_point[0]); - } else { - info->RegisterParameter(selectivity->inflection_point[0]); - } + LogisticSelectivityInterface() : SelectivityInterfaceBase() { } - 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) { - info->RegisterParameterName("logistic selectivity slope"); - if (this->slope.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->slope[0]); - } else { - info->RegisterParameter(selectivity->slope[0]); - } + + virtual ~LogisticSelectivityInterface() { } - info->variable_map[this->slope.id_m] = &(selectivity)->slope; - // add to Information - info->selectivity_models[selectivity->id] = selectivity; + /** @brief returns the id for the logistic selectivity interface */ + virtual uint32_t get_id() { + return this->id; + } + + /** @brief evaluate the logistic selectivity function + * @param x The independent variable in the logistic function (e.g., age or + * size in selectivity). + */ + virtual double evaluate(double x) { + fims_popdy::LogisticSelectivity LogisticSel; + LogisticSel.inflection_point.resize(1); + LogisticSel.inflection_point[0] = this->inflection_point.value_m; + LogisticSel.slope.resize(1); + LogisticSel.slope[0] = this->slope.value_m; + return LogisticSel.evaluate(x); + } + + virtual void finalize() { + + if (this->finalized) { + //log warning that finalize has been called more than once. + FIMS_WARNING_LOG("Logistic Selectivity " + fims::to_string(this->id) + " has been finalized already."); + } + + this->finalized = true; //indicate this has been called already + + std::shared_ptr > info = + fims_info::Information::GetInstance(); + - return true; - } + //set default values as initial values + this->estimated_inflection_point = this->inflection_point.value_m; + this->estimated_slope = this->slope.value_m; - /** @brief this adds the parameter values and derivatives to the TMB model - * object */ - virtual bool add_to_fims_tmb() { - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); + fims_info::Information::selectivity_models_iterator it; - return true; - } + //search for maturity in Information + it = info->selectivity_models.find(this->id); + //if not found, just return + if (it == info->selectivity_models.end()) { + FIMS_WARNING_LOG("Logistic Selectivity " + fims::to_string(this->id) + " not found in Information."); + return; + } else { + std::shared_ptr > sel = + std::dynamic_pointer_cast >(it->second); + + // if the parameter was estimated, set set the estimated value. + if (this->inflection_point.estimated_m) { + this->estimated_inflection_point = sel->inflection_point[0]; + } + + if (this->slope.estimated_m) { + this->estimated_slope = sel->slope[0]; + } + } + } + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\":\"selectivity\",\n"; + ss << " \"type\": \"Logistic\",\n"; + ss << " \"id\": " << this->id << ",\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"inflection_point\",\n"; + ss << " \"id\":" << this->inflection_point.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->inflection_point.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_inflection_point << ",\n"; + ss << " \"is_estimated\":" << this->inflection_point.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->inflection_point.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"slope\",\n"; + ss << " \"id\":" << this->slope.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->slope.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_slope << ",\n"; + ss << " \"is_estimated\":" << this->slope.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->slope.is_random_effect_m << "\n }\n"; + + + ss << "}"; + + return ss.str(); + } + + +#ifdef TMB_MODEL + + template + bool add_to_fims_tmb_internal() { + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + 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) { + info->RegisterParameterName("logistic selectivity inflection_point"); + if (this->inflection_point.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->inflection_point[0]); + } 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) { + info->RegisterParameterName("logistic selectivity slope"); + if (this->slope.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->slope[0]); + } else { + info->RegisterParameter(selectivity->slope[0]); + } + } + info->variable_map[this->slope.id_m] = &(selectivity)->slope; + + // add to Information + info->selectivity_models[selectivity->id] = selectivity; + + return true; + } + + /** @brief this adds the parameter values and derivatives to the TMB model + * object */ + virtual bool add_to_fims_tmb() { + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + + return true; + } #endif }; @@ -144,112 +225,226 @@ class LogisticSelectivityInterface : public SelectivityInterfaceBase { * instantiate from R: logistic_selectivity <- new(logistic_selectivity) */ class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase { - public: - Parameter inflection_point_asc; /**< the index value at which the response +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 + 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 */ - - DoubleLogisticSelectivityInterface() : SelectivityInterfaceBase() {} - - virtual ~DoubleLogisticSelectivityInterface() {} - - /** @brief returns the id for the double logistic selectivity interface */ - virtual uint32_t get_id() { return this->id; } - - /** @brief evaluate the double logistic selectivity function - * @param x The independent variable in the logistic function (e.g., age or - * size in selectivity). - */ - 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; - DoubleLogisticSel.slope_asc.resize(1); - DoubleLogisticSel.slope_asc[0] = this->slope_asc.value_m; - DoubleLogisticSel.inflection_point_desc.resize(1); - DoubleLogisticSel.inflection_point_desc[0] = - this->inflection_point_desc.value_m; - DoubleLogisticSel.slope_desc.resize(1); - DoubleLogisticSel.slope_desc[0] = this->slope_desc.value_m; - return DoubleLogisticSel.evaluate(x); - } + Parameter slope_desc; /**< the width of the curve at the inflection_point */ -#ifdef TMB_MODEL + + double estimated_inflection_point_asc; + double estimated_slope_asc; + double estimated_inflection_point_desc; + double estimated_slope_desc; + + + DoubleLogisticSelectivityInterface() : SelectivityInterfaceBase() { + } + + virtual ~DoubleLogisticSelectivityInterface() { + } - template - bool add_to_fims_tmb_internal() { - std::shared_ptr > info = - fims_info::Information::GetInstance(); - - 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) { - info->RegisterParameterName("double logistic selectivity inflection_point_asc"); - if (this->inflection_point_asc.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->inflection_point_asc[0]); - } else { - info->RegisterParameter(selectivity->inflection_point_asc[0]); - } + /** @brief returns the id for the double logistic selectivity interface */ + virtual uint32_t get_id() { + return this->id; } - 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) { - info->RegisterParameterName("double logistic selectivity slope_asc"); - if (this->slope_asc.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->slope_asc[0]); - } else { - info->RegisterParameter(selectivity->slope_asc[0]); - } + + /** @brief evaluate the double logistic selectivity function + * @param x The independent variable in the logistic function (e.g., age or + * size in selectivity). + */ + 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; + DoubleLogisticSel.slope_asc.resize(1); + DoubleLogisticSel.slope_asc[0] = this->slope_asc.value_m; + DoubleLogisticSel.inflection_point_desc.resize(1); + DoubleLogisticSel.inflection_point_desc[0] = + this->inflection_point_desc.value_m; + DoubleLogisticSel.slope_desc.resize(1); + DoubleLogisticSel.slope_desc[0] = this->slope_desc.value_m; + return DoubleLogisticSel.evaluate(x); } - 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) { - info->RegisterParameterName("double logistic selectivity inflection_point_desc"); - if (this->inflection_point_desc.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->inflection_point_desc[0]); - } else { - info->RegisterParameter(selectivity->inflection_point_desc[0]); - } + + + virtual void finalize() { + + if (this->finalized) { + //log warning that finalize has been called more than once. + FIMS_WARNING_LOG("Double Logistic Selectivity " + fims::to_string(this->id) + " has been finalized already."); + } + + this->finalized = true; //indicate this has been called already + + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + + //set default values as initial values + this->estimated_inflection_point_asc = this->inflection_point_asc.value_m; + this->estimated_slope_asc = this->slope_asc.value_m; + this->estimated_inflection_point_desc = this->inflection_point_desc.value_m; + this->estimated_slope_desc = this->slope_desc.value_m; + + fims_info::Information::selectivity_models_iterator it; + + //search for maturity in Information + it = info->selectivity_models.find(this->id); + //if not found, just return + if (it == info->selectivity_models.end()) { + FIMS_WARNING_LOG("Double Logistic Selectivity " + fims::to_string(this->id) + " not found in Information."); + return; + } else { + std::shared_ptr > sel = + std::dynamic_pointer_cast >(it->second); + + // if the parameter was estimated, set set the estimated value. + if (this->inflection_point_asc.estimated_m) { + this->estimated_inflection_point_asc = sel->inflection_point_asc[0]; + } + + if (this->slope_asc.estimated_m) { + this->estimated_slope_asc = sel->slope_asc[0]; + } + + if (this->inflection_point_desc.estimated_m) { + this->estimated_inflection_point_desc = sel->inflection_point_desc[0]; + } + + if (this->slope_desc.estimated_m) { + this->estimated_slope_desc = sel->slope_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) { - info->RegisterParameterName("double logistic selectivity slope_desc"); - if (this->slope_desc.is_random_effect_m) { - info->RegisterRandomEffect(selectivity->slope_desc[0]); - } else { - info->RegisterParameter(selectivity->slope_desc[0]); - } + + virtual std::string to_json() { + std::stringstream ss; + + ss << "\"module\" : {\n"; + ss << " \"name\": \"selectivity\",\n"; + ss << " \"type\": \"DoubleLogistic\",\n"; + ss << " \"id\": " << this->id << ",\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"inflection_point_asc\",\n"; + ss << " \"id\":" << this->inflection_point_asc.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->inflection_point_asc.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_inflection_point_asc << ",\n"; + ss << " \"is_estimated\":" << this->inflection_point_asc.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->inflection_point_asc.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"slope_asc\",\n"; + ss << " \"id\":" << this->slope_asc.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->slope_asc.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_slope_asc << ",\n"; + ss << " \"is_estimated\":" << this->slope_asc.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->slope_asc.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"inflection_point_desc\",\n"; + ss << " \"id\":" << this->inflection_point_desc.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->inflection_point_desc.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_inflection_point_desc << ",\n"; + ss << " \"is_estimated\":" << this->inflection_point_desc.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->inflection_point_desc.is_random_effect_m << "\n },\n"; + + ss << " \"parameter\": {\n"; + ss << " \"name\": \"slope_desc\",\n"; + ss << " \"id\":" << this->slope_desc.id_m << ",\n"; + ss << " \"type\": \"scalar\",\n"; + ss << " \"value\":" << this->slope_desc.value_m << ",\n"; + ss << " \"estimated_value\":" << this->estimated_slope_desc << ",\n"; + ss << " \"is_estimated\":" << this->slope_desc.estimated_m << ",\n"; + ss << " \"is_random_effect\":" << this->slope_desc.is_random_effect_m << "\n }\n"; + + + ss << "}"; + + return ss.str(); } - info->variable_map[this->slope_desc.id_m] = &(selectivity)->slope_desc; - // add to Information - info->selectivity_models[selectivity->id] = selectivity; - return true; - } +#ifdef TMB_MODEL - /** @brief this adds the parameter values and derivatives to the TMB model - * object */ - virtual bool add_to_fims_tmb() { - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); - this->add_to_fims_tmb_internal(); + template + bool add_to_fims_tmb_internal() { + std::shared_ptr > info = + fims_info::Information::GetInstance(); + + 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) { + info->RegisterParameterName("double logistic selectivity inflection_point_asc"); + if (this->inflection_point_asc.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->inflection_point_asc[0]); + } 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) { + info->RegisterParameterName("double logistic selectivity slope_asc"); + if (this->slope_asc.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->slope_asc[0]); + } 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) { + info->RegisterParameterName("double logistic selectivity inflection_point_desc"); + if (this->inflection_point_desc.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->inflection_point_desc[0]); + } 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) { + info->RegisterParameterName("double logistic selectivity slope_desc"); + if (this->slope_desc.is_random_effect_m) { + info->RegisterRandomEffect(selectivity->slope_desc[0]); + } else { + info->RegisterParameter(selectivity->slope_desc[0]); + } + } + info->variable_map[this->slope_desc.id_m] = &(selectivity)->slope_desc; + + // add to Information + info->selectivity_models[selectivity->id] = selectivity; + + return true; + } + + /** @brief this adds the parameter values and derivatives to the TMB model + * object */ + virtual bool add_to_fims_tmb() { + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); + this->add_to_fims_tmb_internal(); - return true; - } + return true; + } #endif }; diff --git a/src/Makevars b/src/Makevars index a3b36318d..506bceeb3 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1,4 +1,4 @@ -CXX_STD = CXX11 -PKG_CXXFLAGS = -DTMB_MODEL -DTMB_EIGEN_DISABLE_WARNINGS -w -CXX17STD = -std=c++11 -w +CXX_STD = CXX17 +PKG_CXXFLAGS = -std=c++17 -DTMB_MODEL -DTMB_EIGEN_DISABLE_WARNINGS -w +CXX17STD = -std=c++17 -w diff --git a/src/Makevars.win b/src/Makevars.win index ab39ecce2..8598441dd 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -1,6 +1,6 @@ -CXX_STD = CXX11 +CXX_STD = CXX17 PKG_CXXFLAGS = -DTMB_MODEL -DTMB_EIGEN_DISABLE_WARNINGS -CXX17STD = -std=c++11 +CXX17STD = -std=c++17 CXX14FLAGS = Wa, -mbig-obj -O3 CXX17FLAGS = Wa, -mbig-obj -O3 diff --git a/tests/concurrent/run.sh b/tests/concurrent/run.sh old mode 100755 new mode 100644