forsys-sp / forsysr

An R implementation of the ForSys program
GNU General Public License v3.0
8 stars 3 forks source link

Pass specific weight combination to ForSys rather than min, max, step #74

Closed michelledayusfs closed 1 year ago

michelledayusfs commented 1 year ago

How would we pass a specific objective weight combination to ForSys rather than running the whole suite. For example, if I have two priorities and I just want the balanced scenario (e.g. Pr_1_priority1 == 1 & Pr_2_priority2 == 1)

codyevers commented 1 year ago

By far the easiest way to equally weight two values is to add them together as a new variable, and use that variable as the priority.

I have a new formula for scaling between two weights that I still need to incorporate into forsys that does a better job scaling between two variables.

michelledayusfs commented 1 year ago

We just need to be flexible to a wide variety of objectives. Like net revenue can be negative.

michelledayusfs commented 1 year ago

@codyevers The issue defined above is not exactly matching your response. If I have three priorities and I want p#1 to be a weight of 1 and p#2 to be a weight of 5 and p#3 to be a weight of 1, how would I pass that specific weight combination to ForSys, rather than having to screen the outputs to search for (Pr_1_p#1 == 1 & Pr_2_p#2 == 5 & Pr_3_p#3 == 1).

codyevers commented 1 year ago

Great, I understand. Trying to think of the best way to handle this without too much work. Also, should this be an external function similar to how we calculate spm and pcp values? The easiest format would be something like

p1_w = 1
p2_w = 2
data new <- data %>% 
     calculate_spm(fields = c('priority1', 'priority2') %>%
     mutate(combined_priority = priority1 * p1_w + priority2 * p2_w)
forsys::run(
     stand_data = data_new,
     scenario_priorities = 'combined_priority'),
     ...
)

We can create some simple function similar to calculate_spm called `combine_priorities' where someone would pass two or more field names and then a vector of numbers with an equal length representing the weights. Something like...

data_new <- data %>%
     combine_priorities(fields = c('priority1', 'priority2','priority3'), weights = c(1,2,1))

@michelledayusfs would that work?

michelledayusfs commented 1 year ago

Rachel and I met to go over this, and yes, I think this would work. So,

  1. Yes, call this as an external function. as in combine_priorities above.
  2. Rachel has confirmed that the math you have above is correct, as long as it is generalized for multiple priorities. I don't know how many google will have, so if there is a way to NOT limit the number, that is preferable.
codyevers commented 1 year ago

I've added a new function called `combine_priorities' that works like this...

combine_priorities(
  stands = test_forest, 
  fields = c('priority1','priority2','priority3'), 
  weights = c(3,1,1), 
  new_field = 'new_priority')
michelledayusfs commented 1 year ago

@codyevers How do you call this function? This does not work (with or without the forsys):

forsys::combine_priorities(
  stands = shp, 
  fields = c('Am4RevBio_SPM','prob_8p_SPM','res_depart_SPM'), 
  weights = c(5,1,1), 
  new_field = 'preset_priority')
michelledayusfs commented 1 year ago

Test script to explore outputs with preset objective weights and full spectrum of weight combos. Testing_prioritycall.txt

michelledayusfs commented 1 year ago

I tested this with predefined planning areas just to confirm it was not something with the forsys/patchmax integration. It is not. I get different outcomes with predefined planning areas as well. This is a faster test.

michelledayusfs commented 1 year ago

@codyevers I wonder if the issue we are finding is due to using three priorities which we typically never do for our runs. The multiple priorities code (>2 priorities) was written by Luke on the Stanislaus. We did test it to make sure it was working but maybe we missed something.

weight_priorities <- function(numPriorities, weights = c("1 1 1")){
  if(numPriorities == 1)
    return(data.table::data.table(1))
  weights <- strtoi(unlist(strsplit(weights, " ")))
  weights <- seq(weights[1], weights[2], weights[3])
  # Updates by Luke Wilkerson to incorporate multiple priorities.
  weightPermute <- (gtools::permutations(length(weights), numPriorities, weights, repeats.allowed=TRUE))
  weightprops <- proportions(weightPermute, 1)
  weightPermute <- data.table::data.table(weightPermute)
  uniqueWeightCombinations <- weightPermute[!duplicated(weightprops) & rowSums(weightPermute) != 0, ]

  return(uniqueWeightCombinations)
}
michelledayusfs commented 1 year ago

Nope. I just tested it. Filtering for a specific set of scenario weights with a forsys run leads to higher levels of objective than passing the specific weight combination to forsys.

codyevers commented 1 year ago

I've created a new branch to resolve this. It's an opportunity to review and clean up some of these early base functions

codyevers commented 1 year ago

Notes: I've replaced the previous set_up_priorities with the new combine_priorities function to avoid duplication and ensure consistency. I fixed a problem in the (new) combine_priorities function that was likely what lead to the difference when the priority weights were done outside of forsys as opposed to part of the weighting loop. Tomorrow, I'll merge this back into the main branch and Michelle can rerun her earlier tests to see if this issue is now resolved.

codyevers commented 1 year ago

@michelledayusfs The combine priorities should now be fixed and ready for testing. I'm going to assign the issue to you and move it to 'test_and_verify'. If someone wanted to run a specific weighting combination, they'd run combine_priorities outside of forsys, provide the priority fields and respective weights. This creates a new variable with the combined weight which would then be set as the priority when running forsys.

michelledayusfs commented 1 year ago

proj_id and treatment_rank no longer agree. ETrt_weightedPriority is not in descending order based on treatment_rank. I think we need to schedule a meeting to go through this together. I can post the script and outputs if it helps.

michelledayusfs commented 1 year ago

@codyevers This is working with predefined planning areas. Are we ready to test with patchmax?

codyevers commented 1 year ago

Great to hear! Yes, it ‘should’ work with Patchmax. Make sure to do the 100% search though.

Message ID: ***@***.***>
michelledayusfs commented 1 year ago

Working with predefined planning areas and patchmax.

Testing_prioritycall.txt