Skip to content

Commit

Permalink
Debug utilities, small fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kuadrat committed Nov 14, 2023
1 parent 5a96074 commit 6a48ace
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 71 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: growR
Type: Package
Version: 1.0.9.9000
Version: 1.0.9.9001
Date: 2023-09-27
Authors@R: person(
given = "Kevin",
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export(add_lines)
export(analyze_parameter_scan)
export(atmospheric_CO2)
export(box_smooth)
export(browse)
export(browse_end)
export(build_functional_group)
export(create_combinations)
export(create_example_environment)
Expand Down
12 changes: 11 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# growR 1.0.1
# growR 1.1.0

## Added

Expand All @@ -16,6 +16,11 @@
* S3 dispatch for plot method of `ModvegeSite` objects -> `plot(mvs)` is now
possible if `mvs` is a `ModvegeSite` instance.

* `ParameterData` input checking: throws error on duplicate input parameter
name.

* Debug utility conveniences `browse` and `browse_end`.

## Changed

* Input data CSV files are now actual CSV files, instead of
Expand All @@ -33,6 +38,9 @@

* autocut: `get_annual_gross_yield` was incorrectly hardcoded to return 1.

* `ParameterData$set_parameters` now updates initial condition values, if
applicable.

## Removed

* Removed superfluous weather inputs.
Expand All @@ -41,6 +49,8 @@

* Redundant argument *store_results* in `growR_run_loop`.

* `SEA` symmetrization around 1 is not enforced anymore.

# growR 1.0.0

* Initial CRAN submission.
Expand Down
13 changes: 11 additions & 2 deletions R/environment.R
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ ModvegeEnvironment = R6Class(
input_dir = NULL) {
# Set instance variables
self$site_name = site_name
self$run_name = run_name
self$run_name_in_filename = self$make_filename_for_run(run_name)
self$set_run_name(run_name)
self$years = years
# Revert to defaults for the not provided values.
if (param_file == "-") {
Expand Down Expand Up @@ -107,6 +106,16 @@ ModvegeEnvironment = R6Class(
self$load_inputs()
},

#' @description
#' Set run name and update *run_name_in_filename*.
#'
#' @param run_name Str. New value of `self$run_name`.
#'
set_run_name = function(run_name) {
self$run_name = run_name
self$run_name_in_filename = self$make_filename_for_run(run_name)
},

#' @description Load simulation inputs.
#'
#' Stores parameters, management and weather data from files specified in
Expand Down
5 changes: 1 addition & 4 deletions R/modvegesite.R
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ ModvegeSite = R6Class(
#-Public-attributes-------------------------------------------------------------
#' @field time_step Used time step in the model in days (untested).
time_step = 1.,
#' @field state_variable_namse Vector containing the names of the model's
#' @field state_variable_names Vector containing the names of the model's
#' state variables.
state_variable_names = NULL,
#' @field n_state_variables Number of state variables.
Expand Down Expand Up @@ -538,9 +538,6 @@ ModvegeSite = R6Class(
self[["OMDGV"]][1] = P$OMDGV0
self[["OMDGR"]][1] = P$OMDGR0

# (minSEA + maxSEA)/2 = 1
self$parameters[["minSEA"]] = 2 - P[["maxSEA"]]

# Management:
# Initialize a pointer that indicates whether there has been a cut
# during reproductive growth. In this case, reproductive growth is
Expand Down
11 changes: 5 additions & 6 deletions R/parameter_scan.R
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,6 @@ analyze_parameter_scan = function(parameter_scan_results, datafile = "",
}
# Reduce to relevant years
relevant_data = measured_data[measured_data$year %in% years, ]
# Construct a selector for the DOYs present in relevant data
mask = relevant_data$DOY + 365 * (relevant_data$year - relevant_data$year[1])
# Calculate measured cBM_end
measured_cBM_ends = c()
for (year in years) {
Expand All @@ -206,21 +204,22 @@ analyze_parameter_scan = function(parameter_scan_results, datafile = "",
cBM_end = c()
for (i_year in 1:n_years) {
mv = modvegesites[[i_year]]
cBM = c(cBM, mv$cBM)
mask = relevant_data$DOY[relevant_data$year == years[i_year]]
cBM = c(cBM, mv$cBM[mask])
cBM_end = c(cBM_end, mv$cBM[length(mv$cBM)])
smoothed = box_smooth(mv$dBM, box_width = smooth_interval)
dBM = c(dBM, smoothed)
dBM = c(dBM, smoothed[mask])
}
results[[combination]][["cBM"]] = list()
results[[combination]][["dBM"]] = list()
results[[combination]][["cBM_end"]] = list()
# Employ performance metrics
for (metric in metrics_to_use) {
# cBM
m_cBM = metric_map[[metric]][["func"]](cBM[mask], relevant_data$cBM)
m_cBM = metric_map[[metric]][["func"]](cBM, relevant_data$cBM)
results[[combination]][["cBM"]][[metric]] = m_cBM
# dBM
m_dBM = metric_map[[metric]][["func"]](dBM[mask], relevant_data$dBM)
m_dBM = metric_map[[metric]][["func"]](dBM, relevant_data$dBM)
results[[combination]][["dBM"]][[metric]] = m_dBM
# cBM_end
m_cBM_end = metric_map[[metric]][["func"]](cBM_end, measured_cBM_ends)
Expand Down
45 changes: 33 additions & 12 deletions R/parameters.R
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ ModvegeParameters = R6Class(
#' @field fg_parameter_names Names of vegetation parameters defined by the
#' functional group composition.
fg_parameter_names = NULL,
#' @field initial_condition_names Names of initial conditions.
initial_condition_names = c(initial_condition_names,
"WHC", "maxOMDGV", "maxOMDGR"),
#' @field param_file Name of the parameter file from which initial parameter
#' values were read.
param_file = NULL,
Expand Down Expand Up @@ -179,17 +182,7 @@ ModvegeParameters = R6Class(
# Update the functional group parameters in P.
self$update_functional_group()

# Set initial conditions
for (name in initial_condition_names) {
old_name = name
new_name = paste0(old_name, "0")
self[[new_name]] = self[[old_name]]
}

# Set some more initial values
self[["WR0"]] = self[["WHC"]]
self[["OMDGV0"]] = self[["maxOMDGV"]]
self[["OMDGR0"]] = self[["maxOMDGR"]]
private$update_initial_conditions()
},

#' @description Savely update the given parameters
Expand All @@ -205,11 +198,17 @@ ModvegeParameters = R6Class(
for (i in 1:length(params)) {
name = param_names[[i]]
self[[name]] = params[[i]]
# :TODO: Also update initial values XXX0.
}
# Check if FG composition needs to be updated
if (any(param_names %in% c("w_FGA", "w_FGB", "w_FGC", "w_FGD"))) {
self$update_functional_group()
}

# Check if initial conditions need updating
if (any(param_names %in% self$initial_condition_names)) {
private$update_initial_conditions()
}
},

#' @description Update functional group parameters
Expand All @@ -230,7 +229,8 @@ ModvegeParameters = R6Class(
}
},

#' @description Parameter Sanity Check
#' @description
#' Parameter Sanity Check
#' Ensure that the supplied *params* are valid ModVege parameters and,
#' if requested, check that all required parameters are present.
#' Issues a warning for any invalid parameters and throws an error if
Expand All @@ -247,6 +247,11 @@ ModvegeParameters = R6Class(
#'
#' @md
check_parameters = function(param_names, check_for_completeness = TRUE) {
# Check for duplicate param names
if (length(param_names) != length(unique(param_names))) {
logger("Non-unique parameter names in supplied parameters.",
level = ERROR)
}
param_file = self$param_file
if (check_for_completeness) {
# Give error if an argument is missing.
Expand All @@ -271,6 +276,22 @@ ModvegeParameters = R6Class(
return(not_known)
}
)
),

private = list(
## Set initial conditions
update_initial_conditions = function() {
for (name in initial_condition_names) {
old_name = name
new_name = paste0(old_name, "0")
self[[new_name]] = self[[old_name]]
}

# Set some more initial values
self[["WR0"]] = self[["WHC"]]
self[["OMDGV0"]] = self[["maxOMDGV"]]
self[["OMDGR0"]] = self[["maxOMDGR"]]
}
)
)

68 changes: 66 additions & 2 deletions R/utilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ check_for_package = function(package, stop = TRUE) {
return(TRUE)
}

#' Constants representing different debug levels to be used internally.
## Constants representing different debug levels to be used internally.
ERROR = 1
WARNING = 2
INFO = 3
DEBUG = 4
TRACE = 5

#' Names of debug levels.
## Names of debug levels.
DEBUG_LEVELS = c("ERROR", "WARNING", "INFO", "DEBUG", "TRACE")

#' Set verbosity of growR output.
Expand Down Expand Up @@ -373,3 +373,67 @@ ensure_table_columns = function(required, data, data_name = "the data table") {
}
}

#' Create unique DOY + year identifier
#'
#' Return numbers of the form YYYYDDD where YYYY is the year and DDD the DOY.
#'
#' @param years int vector.
#' @param DOYs int vector of same length as *years*.
#'
#' @return int vector of same length as *years* containing numbers of the
#' form YYYYDDD, where the first four digits represent a year and the last
#' four represent a DOY.
make_yearDOY = function(years, DOYs) {
return(1000 * years + DOYs)
}

#' Debugging utilities
#'
#' @description
#' Debug specified function *func* by entering a [browser()] right at the
#' beginning ([browse()]) or end ([browse_end()]) of the function.
#'
#' @details
#' These are convenience shorthands for R's builtin debug tools, like
#' [debugonce()] and the [trace()]/[untrace()] combination.
#'
#' @param func An R function to be browsed.
#' @param ... Arguments to the function *func* that is to be browsed.
#'
#' @return Returns the result of `func(...)`. Enters a [browser()].
#'
#' @examplesIf interactive()
#' # Define a simple function for this example
#' my_func = function(a) { for (i in 1:5) { a = a + i }; return(a) }
#'
#' # Enter a browser at the beginning of the function
#' browse(my_func, 0)
#'
#' # Enter a browser at the end of the function. This allows us to inspect
#' # the function's local variables without having to go through the whole loop.
#' browse_end(my_func, 0)
#'
#' @seealso [browser()], [debugonce()], [trace()]
#'
#' @md
#' @export
browse = function(func, ...) {
debugonce(func)
func(...)
}

#' Enter browser at end of function execution
#'
#' @describeIn browse
#' Enter [browser()] at the end of the function call to `func(...)`. This
#' only works, if the function can execute without error until its end.
#' Otherwise, the error will be thrown.
#'
#' @seealso [trace()]
#' @md
#' @export
browse_end = function(func, ...) {
trace(func, exit = browser, where = environment())
func(...)
}

8 changes: 6 additions & 2 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ reference:
- contents:
- PscanPlotter
- Combinator
- title: Debug Tools
desc: Utilities that may be of help if things go wrong.
- contents:
- browse
- browse_end
- logger
- title: Other
- contents:
- DEBUG_LEVELS
- ERROR
- SEA
- aCO2_inverse
Expand All @@ -82,7 +87,6 @@ reference:
- get_relative_cut_contribution
- get_site_name
- growR_package_options
- logger
- management_parameters
- metric_map
- parse_year_strings
Expand Down
16 changes: 0 additions & 16 deletions man/DEBUG_LEVELS.Rd

This file was deleted.

16 changes: 0 additions & 16 deletions man/ERROR.Rd

This file was deleted.

Loading

0 comments on commit 6a48ace

Please sign in to comment.