Writing a custom risk factor

As explained earlier, a risk factor will typically define a number of exposure categories, and each category will be assigned one or more relative risks (e.g., for chronic disease incidence). The primary concerns when writing a custom risk factor are:

  • Identifying appropriate exposure categories;

  • Identifying which rates will be modified by these exposure categories;

  • Defining the relative risks for each rate, for each exposure category; and

  • Defining transition rates between exposure categories (if applicable).

Once these concerns have been addressed, the input data requirements can be identified, and input data tables can be prepared.

Structure of a risk factor component

A risk factor component will comprise the following methods:

  • A constructor (__init__) that will normally accept two arguments:

    • The self parameter (a reference to the component instance); and

    • A name that will be used to identify this risk factor, and which may be used in the configuration section of a simulation definition in order to define settings for this risk factor.

  • A setup(self, builder) method that will:

    • Load any required input value or rate tables, including the initial prevalence for each exposure category.

    • Read any risk-factor-specific settings from builder.configuration.

    • Register value and/or rate modifiers.

    • Register a time-step event handler to, e.g., move people from one exposure category to another (if required).

  • Some number of value and/or rate modifiers.

  • The time-step event handler (if required).

  • If you anticipate applying interventions that affect the prevalence of exposure categories, it may be convenient to also include a method that returns the column name for each exposure category.

Example of an intervention component

As an example, we will walk through each of these methods for the DelayedRisk risk factor, which was created to model the effects of tobacco smoking.

The constructor

This component has one required argument for the constructor, which is the name of the risk factor. Note that the constructor defines the default configuration settings for this component, because this depends on knowing the risk factor’s name.

The setup method

The setup() method performs several necessary house-keeping tasks:

  • It reads the configuration settings.

  • It loads the initial prevalence for each exposure category.

  • It loads the incidence and remission rates, and registers these rates so that they will be available at each time-step.

  • It request access to the all-cause mortality rate, and loads the relative risk of mortality for each exposure category, so that it can determine the excess mortality produced by this risk factor.

  • It registers rate modifiers for each disease that is affected by this risk factor (implemented by the register_modifier method, described below).

  • It loads the disease-specific relative risks for each exposure category.

  • It adds an initialization handler to create a column for each exposure category, and populate them with the initial prevalence.

  • It loads the effects that a tobacco tax would have on the incidence and remissions rates.

  • It registers an event handler that will be called before each time-step (by selecting the “time_step__prepare” event) that will move people from one post-cessation category to the next.

  • It defines the columns that it will need to access, and stores this view in self.population_view.

The initialization method

The on_initialize_simulants() method creates a column for each of the exposure categories (with separate columns for the BAU and intervention scenarios), populates them with the initial prevalence values, and updates the underlying table.

The rate modifiers

This risk factor can affect an arbitrary number of diseases, and so this component includes the register_modifier() method, which registers modifiers for:

  • The incidence rate of a chronic disease;

  • The excess mortality rate of an acute disease/event; and

  • The disability rate of an acute disease/event.

This approach was used because the component is currently unable to identify whether each disease that it affects is a chronic disease or an acute disease.

The incidence_adjustment() method calculates the mean relative risk in the BAU and intervention scenarios, from which it then calculates the PIF, and modifies the un-adjusted rate accordingly.

The prevalence modifier

The on_time_step_prepare() method modifies the prevalence, so that it takes effect before the time-step itself, and accounts for the normal transitions between exposure categories in both the BAU and intervention scenarios:

  • The incidence rate moves people from the never smoked category to the currently smoking category;

  • The remission rate moves people from the currently smoking category to the 0 years post-cessation category; and

  • People move from the N years post-cessation category to the N+1 years post-cessation category, until they reach 21+ years post-cessation.

  • It also accounts for mortality in each exposure category.

Note

The order in which these transitions are performed is important. First, we accumulate people in the final category, 21+ years post-cessation. Second, we move people from the N years post-cessation category to the N+1 years post-cessation category in reverse-chronological order. Finally, we account for incidence and remission. This will account for the effects of a tobacco tax in the intervention scenario, if the tobacco_tax configuration setting was set to True, and the remission rate in the intervention scenario will be set to zero if the constant_prevalence configuration setting was set to True.

The column name method

For convenience, this component provides the get_bin_names() method that returns a list of the column names for each exposure category, for both the BAU and intervention scenarios.