extending-resources

library(plotly)
#> Loading required package: ggplot2
#> 
#> Attaching package: 'plotly'
#> The following object is masked from 'package:ggplot2':
#> 
#>     last_plot
#> The following object is masked from 'package:stats':
#> 
#>     filter
#> The following object is masked from 'package:graphics':
#> 
#>     layout
library(villager)

Extending Resources

To create resources that have additional properties, subclass the resource class.

To add new members to the resource class,

  1. Copy the resource class source definition
  2. Create the new member variable
  3. Add it as a parameter to the initialize function
  4. Make an entry for it in the as_table function

Resource with an expiration date

To demonstrate how to subclass and run a model with a custom resource class, consier an example of corn and rice resources that expire. To do this, a new variable is added to the resource class, creation_date which gets updated when the resource is created. When the model runs, the date at each time step is used to check against the creation date of each resource.

Custom resource class

resource_expiration <- R6::R6Class("resource",
  cloneable = TRUE,
  public = list(
    name = NA,
    quantity = NA,
    creation_date = NA,

    #' Creates a new resource.
    #'
    #' @description Creates a new resource object
    #' @param name The name of the resource
    #' @param quantity The quantity present
    #' @param creation_date The date that the resource was created
    initialize = function(name = NA, quantity = 0, creation_date=NA) {
      self$name <- name
      self$quantity <- quantity
      self$creation_date <- creation_date # New member variable to track the creation date
    },

    #' Returns a data.frame representation of the resource
    #'
    #' @return A data.frame of resources

    as_table = function() {
      return(data.frame(name = self$name, quantity = self$quantity))
    }
  )
)

Initial Condition

The initial condition is a village that has two resource types, corn and rice.

initial_condition <- function(current_state, model_data, agent_mgr, resource_mgr) {
  for (i in 1:10) {
    name <- runif(1, 0.0, 100)
    new_agent <- agent$new(first_name <- name, last_name <- "Smith")
    agent_mgr$add_agent(new_agent)
  }
  # Create two new resources at the current date (The first day)
  corn <- resource_expiration$new("Corn", 10, current_state$step)
  rice <- resource_expiration$new("Rice", 20, current_state$step)
  resource_mgr$add_resource(corn)
  resource_mgr$add_resource(rice)
}

Model

The model checks the current date against the expiration dates on each resource. When the threshold limits are reached, the quantity is set to zero.

# Create the model that, each day, checks to see whether or not any resource expire
model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
  # Loop over all of the resources and check if any expire
  for (resource in resource_mgr$get_resources()) {
    # Figure out how many days have passed
    days_passed <- current_state$step - resource$creation_date
    if (resource$name == "Corn") {
      if (days_passed > 10 && resource$quantity > 0) {
        print("Setting Corn quantity to 0")
        resource$quantity <- 0
      }
    } else if (resource$name == "Rice" && resource$quantity > 0) {
      if (days_passed > 20) {
        print("Setting Rice quantity to 0")
        resource$quantity <- 0
      }
    }
  }
}

Running

With the required model components complete, we can create a simulation that runs for 15 days. By the end of it, there should be no more corn left, and the rice stocks should still be full.

# Create the village and simulation
coastal_village <- village$new("Expiring_Resources", initial_condition, model, resource_class=)
simulator <- simulation$new(16, villages = list(coastal_village))
simulator$run_model()
#> [1] "Setting Corn quantity to 0"

Results

A timeseries of each resource type is plotted below. The rice resource has clearly not expired while the corn resource has after 10 days.

# Load in data
time_series_data <- readr::read_csv("results/Expiring_Resources/resources.csv")
#> Rows: 32 Columns: 3
#> ── Column specification ────────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (1): name
#> dbl (2): quantity, step
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

# Get unique dates
unique_step<- sort(unique(time_series_data$step))

# Get corn & rice quantities and dates
corn_date_quantities <- dplyr::filter(time_series_data, name=="Corn")
rice_date_quantities <- dplyr::filter(time_series_data, name=="Rice")

# create data frame for sorted data
reordered_time_series <- data.frame(step = unique_step, Corn = 0, Rice = 0)
for (i in 1:nrow(reordered_time_series)){
  reordered_time_series[i,2] = corn_date_quantities[which(corn_date_quantities$step == reordered_time_series$step[i]),2]
  reordered_time_series[i,3] = rice_date_quantities[which(rice_date_quantities$step == reordered_time_series$step[i]),2]
}

# Plot graph
plotly::plot_ly(reordered_time_series, x = ~step) %>% 
  plotly::add_trace(y = ~Corn, name = 'Corn', type = 'scatter', mode = 'lines') %>% 
  plotly::add_trace(y = ~Rice, name = 'Rice', type = 'scatter', mode = 'lines') %>%
  plotly::layout(title = 'Resource Counts', xaxis = list(title = 'Time Step'),
       yaxis = list(title = 'Quantity'), legend = list(title=list(text='Crop Type')))