Skip to content

updating to directly input ACH and infer riskiness. User defined efficacy from delta ACH#142

Open
cwhittaker1000 wants to merge 65 commits into
mainfrom
ach_efficacy_update
Open

updating to directly input ACH and infer riskiness. User defined efficacy from delta ACH#142
cwhittaker1000 wants to merge 65 commits into
mainfrom
ach_efficacy_update

Conversation

@cwhittaker1000

@cwhittaker1000 cwhittaker1000 commented Jan 22, 2026

Copy link
Copy Markdown
Collaborator

As above; this addresses and answers #136 - @geethaj1 will be handling this.

@cwhittaker1000

Copy link
Copy Markdown
Collaborator Author

Aim with this PR is get helios into a position where we're directly inputting ACH values (probably specifying a distribution that we draw from) into the run_function, instead of riskiness parameters (specifying a riskiness distribution, itself derived externally from ACH values, see here).

The aim with doing this is to enable us to calculate efficacy not as a single input value, but as a function of ACH in each location; whilst also retaining the ability to specify riskiness, again in a location specific manner.

This is very rough, but based on our convo today, it seems like there are 4 broad pieces of work to be done here (not necessarily in this order):

  1. Change the arguments and inputs of run_simulation (and the associated functions for generating the parameter list) to take in parameters that specify ACH values, rather than riskiness values. For example, these might be the setting-specific mean and sd of a normal distribution (but let's chat more about the exact parameterisation).
  2. Change the arguments and inputs of run_simulation to take in parameters that specify the relationship between ACH and efficacy, conditional on e.g. some max_efficacy (or similar, we can talk about the exact parameterisation).
  3. Use those parameters inside run_simulation (possibly within their own function, which is called within run_simulation) to draw an ACH for each location (e.g. for each location of a setting type, draw from a normal with setting-type specific ACH mean and sd defined in 1))
  4. Use those ACHs for each location to get a corresponding riskiness (probably using the framework we initially developed in
    this).
  5. Use those ACHs to also calculate for each location (of each setting type) an intervention efficacy that is calculated based on their ACH and the new parameter inputs specified in 1).

@geethaj1

geethaj1 commented Feb 11, 2026

Copy link
Copy Markdown
Collaborator

Updates:

  1. Code to explore normal and lognormal distributions of ACH and impact on riskiness distributions in R/normal_dist_ACH_exploration.R and R/lognormal_ACH_dist.R

  2. Created script r/setting_specific_ACH.R which includes:

  • function to draw ACH values from truncated normal distribution generate_setting_specific_ach()
  • function to convert raw ACH to riskiness value convert_ach_to_riskiness(), using the W-R model and parameters
  • placeholder function to calculating efficacy from ach calculate_efficacy_from_ach() (function not defined yet)
  • function for user to specify ACH distribution parameters set_setting_specific_ach()
  1. Modified parameters.R
  • added W_R model parameters (emission rate, decay rate, p_inf, etc)
  • added setting specific room volumes
  • added ACH distribution parameters (mean, sd) for each setting type
  • added efficacy parameters (placeholders, haven't defined function)
  1. Modified variables.R
    -replaced riskiness generation with ACH
  • (placeholder) location specific efficacies based on ACH
    I

Comment thread R/parameters.R Outdated
Comment thread R/parameters.R Outdated
Comment thread R/setting_specific_ach.R Outdated
Comment thread R/setting_specific_ach.R Outdated
Comment thread R/setting_specific_ach.R Outdated
@geethaj1

Copy link
Copy Markdown
Collaborator

Summary of changes:

  1. set_setting_specific_riskiness.R is replaced by set_setting_specific_ach.R where user specifies the parameters of ach truncated normal distributions for each setting type instead of specifying the parameters of riskiness truncated lognormal distributions through user-facing set_setting_specific_ach() function.
  2. ACH values are converted to riskiness using W-R through the convert_ach_to_riskiness()
  3. ACH values are also used to calculate efficacy, where the user can choose from a constant or sigmoid function to define the relationship between ach and efficacy of intervention. The user does this through the set_uvc_ach() function

@geethaj1 geethaj1 changed the title updating to directly input ACH and infer riskiness and intervention efficacy from that updating to directly input ACH and infer riskiness. User defined efficacy from delta ACH May 18, 2026
@cwhittaker1000

Copy link
Copy Markdown
Collaborator Author

@geethaj1 - quick q as I'm running through the code. Are there any files in inst that directly relate to or inform the code/default parameters in the model? If so, I'm thinking we should make a separate folder in inst called VIP or similar where we keep track of all these scripts. I'm motivated by the fact I keep trying to find that lognormal params script I wrote ages ago in inst whenever we want to look something related to that up. Would be good to have them all in one place - do you have any scripts like that or are they all mainly just for testing the model after you've made changes?

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

@cwhittaker1000 cwhittaker1000 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff @geethaj1 - really impressive work here. Everything looks broadly right to me - some minor comments/questions enclosed and I think the big piece is tidying this up and documentation improvements ahead of merge. Congrats!

Comment thread R/parameters.R
volume_per_person_leisure = 8, # 2m^2*4M
volume_per_person_household = 50, # 20m^2 * 2.5m

# W-R parameters

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a conversation about how much we want to expose these parameters - I think doing so is fine but useful to have a conversation about helper functions vs forcing users to input these directly etc.

Comment thread R/parameters.R Outdated
Comment thread R/parameters.R
# far_uvc_household_sigmoid_x0 = NULL,

# Intervention parameters (Wells-Riley ACH-based efficacy):
intervention_joint_active = FALSE,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any of these parameters are currently documented in the above documentation on inputs or elsewhere? I'm currently having to infer and understand them based on context and reading other parts of the codebase, which is time consuming. Can you make sure all these are documented and described please?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added documentation for volume per person parameters, Wells Riley parameters, and intervention parameters

Comment thread R/parameters.R
intervention_household_covered = NULL,

# Room Size Per Individual Parameters:
size_per_individual_workplace = 1,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need these if we have the volume parameters above?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the volumes are used in the W-R calculations, but right now room size per individual is being used in the coverage allocation when coverage_target = "square_footage". We could change it so we change the square-footage option to volume, and then have coverage allocated by volume, which could be good to do

Comment thread R/parameters.R Outdated
Comment thread R/interventions.R
# calculation runs through the same code path.
for (s in c("workplace", "school", "leisure")) {
parameters_list[[paste0("intervention_", s, "_active")]] <- TRUE
parameters_list[[paste0("intervention_", s, "_list")]] <- parameters_list$intervention_joint_list

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this parameter intervention_joint_list - I can't figure it out and where it's used/what for?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the list of things like what it does to modify ACH etc that we discussed?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, intervention_joint_list stores the list of interventions (in this branch its just 1 intervention), and describes the characteristics of the intervention. It's used in calculate_efficacy_from_ach to get information about the interventino, and in generate_joint-intervention_switches for coverage allocation.

Comment thread R/interventions.R
variation_function = NULL,
variation_params = list(),
coverage = NULL) {
list(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need some checks in here - if affected_by_baseline_ach is set to FALSE, then baseline_ach_function should be NULL right?

Related point is that none of these parameters are documented or particularly clear - I think we need clearer documentation of what they are and what they mean/correspond to.

@geethaj1 geethaj1 May 29, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah sorry this is poor naming on my end, I've renamed affected_by_baseline_ach todelta_depends_on_baseline_ach delta_depends_on_baseline_ach , and baseline_ach_function to delta_function, as it is the function to define the delta ACH of an intervention, irrespective of whether it is affected by the baseline .
I've added added roxygen documenting the definitions

Comment thread R/interventions.R Outdated
coverage_target,
coverage_type,
timestep,
...) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having the ... why not just force the user to pass in the list directly?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have edited to force user to pass directly, this was leftover from when I was initially attempting multiple interventions on this branch. Has now been cleaned up and documented

Comment thread R/interventions.R
# Efficacy at location i = 1 - p_post[i] / p_pre[i], where the post-intervention
# alpha is augmented by the sum of intervention deltas (zeroed for uncovered
# locations via the coverage vector).
calculate_efficacy_from_ach <- function(ach_values, parameters_list, setting) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really nice work Geetha!

Comment thread R/interventions.R


# =============================================================================
# Helper functions for ACH / efficacy / UV-C conversions

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haven't looked at the below in detail as presume they're helper functions not used anywhere much. Let me know if that seems wrong

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is right, the helper functions are just there to help the user figure out the appropriate inputs, not used anywhere in the actual model

geethaj1 added 8 commits May 19, 2026 12:49
baseline_ach_function -> delta_function
baseline_ach_params -> delta_params
affected_by_baseline_ach   -> delta_depends_on_baseline_ach
better represents that they describe the delta the intervention adds (and whether that
delta depends on baseline ACH).
… it with intervention documentation and Roxygen
Comment thread R/parameters.R
volume_per_person_workplace = 27, #10m^2 *2.7m
volume_per_person_school = 10, # 3.33m^2 *3m
volume_per_person_leisure = 8, # 2m^2*4M
volume_per_person_household = 50, # 20m^2 * 2.5m

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this isn't currently connected to the square footage per person assumed for coverage allocation etc (or at least, it matches only through the defaults, a user could change this and it might not change the square footage used in coverage allocation). Need to make sure they're joined up if they're not already!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Geetha: maybe just do square footage per person and multiply by heights.

Charlie: yes I like that idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants