Skip to content

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

Open
cwhittaker1000 wants to merge 54 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 54 commits into
mainfrom
ach_efficacy_update

Conversation

@cwhittaker1000
Copy link
Copy Markdown
Collaborator

@cwhittaker1000 cwhittaker1000 commented Jan 22, 2026

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
Copy link
Copy Markdown
Collaborator

geethaj1 commented Feb 11, 2026

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
Comment thread R/parameters.R
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

Comment thread R/parameters.R
Comment thread R/parameters.R Outdated
Comment thread R/parameters.R
Comment thread R/parameters.R Outdated
#ach to efficacy parameters_workplace
far_uvc_workplace_ach_efficacy_relationship = NULL, #constant or sigmoid
far_uvc_workplace_efficacy = NULL, #constant
far_uvc_workplace_max_efficacy = NULL, # sigmoid
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change
far_uvc_workplace_max_efficacy = NULL, # sigmoid
far_uvc_workplace_max_efficacy = NULL, # sigmoid

Comment thread R/parameters.R Outdated
#ach to efficacy parameters_school
far_uvc_school_ach_efficacy_relationship = NULL, #constant or sigmoid
far_uvc_school_efficacy = NULL, #constant
far_uvc_school_max_efficacy = NULL, # sigmoid
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change
far_uvc_school_max_efficacy = NULL, # sigmoid
far_uvc_school_max_efficacy = NULL, # sigmoid

Comment thread R/setting_specific_ach.R Outdated
Comment on lines +83 to +93
set_uvc_ach <- function (parameters_list,
setting,
coverage,
coverage_target,
coverage_type,
timestep,
relationship_type,
max_efficacy,
sigmoid_k,
sigmoid_x0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change
set_uvc_ach <- function (parameters_list,
setting,
coverage,
coverage_target,
coverage_type,
timestep,
relationship_type,
max_efficacy,
sigmoid_k,
sigmoid_x0) {
set_uvc_ach <- function(
parameters_list,
setting,
coverage,
coverage_target,
coverage_type,
timestep,
relationship_type,
max_efficacy,
sigmoid_k,
sigmoid_x0
) {

Comment thread R/setting_specific_ach.R Outdated
Comment on lines +106 to +107


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change

Comment thread R/variables.R Outdated
setting = "household"
)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change

Comment thread R/variables.R Outdated
Comment on lines +276 to +280
if (any(parameters_list$far_uvc_joint,
parameters_list$far_uvc_workplace,
parameters_list$far_uvc_school,
parameters_list$far_uvc_leisure,
parameters_list$far_uvc_household)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change
if (any(parameters_list$far_uvc_joint,
parameters_list$far_uvc_workplace,
parameters_list$far_uvc_school,
parameters_list$far_uvc_leisure,
parameters_list$far_uvc_household)) {
if (
any(
parameters_list$far_uvc_joint,
parameters_list$far_uvc_workplace,
parameters_list$far_uvc_school,
parameters_list$far_uvc_leisure,
parameters_list$far_uvc_household
)
) {

Comment thread R/variables.R Outdated
Comment on lines +288 to +289
parameters_list[paste0("far_uvc_", setting_types, "_efficacy")] <- parameters_list$far_uvc_joint_efficacy
parameters_list[paste0("far_uvc_", setting_types, "_timestep")] <- parameters_list$far_uvc_joint_timestep
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[air] reported by reviewdog 🐶

Suggested change
parameters_list[paste0("far_uvc_", setting_types, "_efficacy")] <- parameters_list$far_uvc_joint_efficacy
parameters_list[paste0("far_uvc_", setting_types, "_timestep")] <- parameters_list$far_uvc_joint_timestep
parameters_list[paste0(
"far_uvc_",
setting_types,
"_efficacy"
)] <- parameters_list$far_uvc_joint_efficacy
parameters_list[paste0(
"far_uvc_",
setting_types,
"_timestep"
)] <- parameters_list$far_uvc_joint_timestep

@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>
Copy link
Copy Markdown
Collaborator Author

@cwhittaker1000 cwhittaker1000 left a comment

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?

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?

Comment thread R/parameters.R Outdated
)
}
}
# # Old targeted_riskiness validation against the removed far_uvc_* config
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.

Same comment as above - I think you can get rid of this and remove the commented code. If you're unsure whether we might need to return to it, save this version of parameters.R in an inst folder called old_scripts or similar. Remember we have version control so can always go back to this commit to view it either way!

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.

Comment thread R/interventions.R
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?

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

geethaj1 added 4 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).
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