Skip to content

Conversation

@RHull-IDM
Copy link
Member

@RHull-IDM RHull-IDM commented Aug 6, 2025

Updated vaccination intervention which now leverages the starsim.Intervention class.

New features:

  • Configurable start and end dates, which can be passed in as date strings or decimal years, e.g. "2001-01-01" or 2001.0
  • Vaccine explicit strains + multivalence: Can now incorporate as many strains as desired in vaccine if provided manually, or will default to most dominant single strain if none provided
  • Immunity waning: vaccines can now be configured with a waning rate and delay

Tests have been added for each of these features as well.

Closes #20

Note: I still need to update the baseline test values before merging.

RHull-IDM added 15 commits July 18, 2025 17:01
… handles waning and multivalent vaccines, as well as flexible scheduling. While the waning does work as expected internally, it is not yet connected to the immunity model.
# Conflicts:
#	rotasim/rotasim_genetics.py
…o update Rota class to always use the vaccine interventions.
…ivery. The delivery class was too inflexible an incomplete, and this simplifies the code as well. Added tests for each of the new intervention features.
@RHull-IDM RHull-IDM requested a review from Suvanthee August 6, 2025 06:26
Copy link
Member

@daniel-klein daniel-klein left a comment

Choose a reason for hiding this comment

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

Hi @RHull-IDM, I added a few comments for your consideration. My quick review focused on the new interventions.py file rather than changes to rotasim or rotasim_genetics. Thanks!

ppl = self.sim.people
if self.sim.ti in self.timepoints:
if self.sim.ti == self.timepoints[0]:
# if there is no strain associated with the product, select the most prevalent strain
Copy link
Member

Choose a reason for hiding this comment

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

So in different sims (e.g. change rand_seed or other parameters), the vaccine might contain different antigens, based on prevalence at the first timepoint of the vaccine? This feels error-prone, consider requiring users to specify g and p.

Copy link
Member Author

Choose a reason for hiding this comment

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

This maintains the behavior of the original model. If @Suvanthee or Kyra or Alicia want to chime in I'm happy to change to whatever makes sense.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The intended behavior was to

  1. Let the model reach an equilibrium for the first 5 years
  2. At 15 years pick the vaccine strain as the most prevalent strain in the last 10 years (skipping the first 5 years where the model is in the initialization phase)

Once the vaccine strain is picked we will not change it and use it in the future for both doses.

I think we should add the behavior where we skip the first 5 (time_to_equilibrium) years because at the start the simulation is very volatile similar to here.

For different seeds and other parameters we may indeed see different strains being picked. Our goal here was to study the effect of targeting the most prevalent strain though a vaccine in many settings. I think the current code achieves that.

An option that allows users to specify the strain would be a great addition too.

Copy link
Member

Choose a reason for hiding this comment

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

Suvanthee is correct that the original intention was to choose the most prevalent strain, even if that change from iteration to iteration. We asked Ryan to add the option to specify vx_strains so that we can maintain consistency in the vaccine strain across iterations as needed (e.g., if want to model specifically the effects of a G1P8 vaccine like Rotarix) - and expect that we will primarily use this functionality moving forward, but retain default behavior of selecting most prevalent strain if vx_strains are not specified.

vx_intv_found = True
break

if not vx_intv_found:
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to run a simulation without the RotaVaxProg?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was previously an integral part of the model and was not separate from the rest of the model logic, so I implemented it this way to maintain consistency. If there's a case for not using the vaccination program I will make it optional.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to have this functionality. Earlier we had a vaccine_hypothesis where this was skipped. But I now realize that I got rid of it while removing the vaccine_hypothesis for simplifying the model

Copy link
Collaborator

@Suvanthee Suvanthee left a comment

Choose a reason for hiding this comment

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

Hi @RHull-IDM This looks great. I am slowly going through the changes. left some comments.

ppl = self.sim.people
if self.sim.ti in self.timepoints:
if self.sim.ti == self.timepoints[0]:
# if there is no strain associated with the product, select the most prevalent strain
Copy link
Collaborator

Choose a reason for hiding this comment

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

The intended behavior was to

  1. Let the model reach an equilibrium for the first 5 years
  2. At 15 years pick the vaccine strain as the most prevalent strain in the last 10 years (skipping the first 5 years where the model is in the initialization phase)

Once the vaccine strain is picked we will not change it and use it in the future for both doses.

I think we should add the behavior where we skip the first 5 (time_to_equilibrium) years because at the start the simulation is very volatile similar to here.

For different seeds and other parameters we may indeed see different strains being picked. Our goal here was to study the effect of targeting the most prevalent strain though a vaccine in many settings. I think the current code achieves that.

An option that allows users to specify the strain would be a great addition too.

ve_s = self.vaccine_efficacy_s_d2[pathogen_strain_type]
else:
raise NotImplementedError(f"Unsupported vaccine dose: {vaccine.dose}")
ve_s = vaccine.product.vaccine_efficacy_s[n_doses][pathogen_match]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the waning immunity should also affect the protection against severe infection. Previsously we only applied the severity reduction when the vaccine immunity has not waned (see if vaccine is not None and not vaccine.is_waned: above).

I think we need to apply the same reduction for the probability of getting a severe case as for vaccine immunity here.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed - behavior should be to apply the same waning multiplicative factor to VE_i and VE_s (or wane total VE and then use the same ratio to calculate VE_i and VE_s at each time step)

Copy link
Member Author

Choose a reason for hiding this comment

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

Added waning to the severity calculation.


def breakdown_vaccine_efficacy(self, ve, x):
"""
Break down the vaccine efficacy into its components
Copy link
Collaborator

Choose a reason for hiding this comment

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

I will send a description for this tomorrow.

vx_intv_found = True
break

if not vx_intv_found:
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to have this functionality. Earlier we had a vaccine_hypothesis where this was skipped. But I now realize that I got rid of it while removing the vaccine_hypothesis for simplifying the model

@RHull-IDM RHull-IDM closed this Oct 20, 2025
@RHull-IDM
Copy link
Member Author

Ended up going a different direction with a full refactor to work better with the latest Starsim version

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.

Refactor vaccination

6 participants