Intervention eligibility

At this point, you should now be able to run multiple simulations with distinct interventions, using default or custom parameters and plot the results. So far we’ve seen interventions that target a model parameter. Now we will see how we can we specify a function that tells FPsim who will receive the intervention. First, import the model and set your default settings.

import fpsim as fp      # Main FPsim module
import sciris as sc     # For utilities
import starsim as ss    # For running multiple sims in parallel
import matplotlib.pyplot as plt  # For plotting
location = 'kenya'
pars = dict(
    n_agents   = 1_000,
    location   = location,
    start_year = 2000, 
    end_year   = 2012,
    exposure_factor = 1.0  # Overall scale factor on probability of becoming pregnant
)

Now, we will modify a ‘state’ value of all eligible women. To see all the states you can select based on, run this code:

from fpsim.defaults import fpmod_states
for i, state in enumerate(fpmod_states): print(f"{i}: {state.name}")
0: on_contra
1: method
2: ti_contra
3: ever_used_contra
4: intent_to_use
5: fertility_intent
6: fertility_intent_cat
7: lam
8: sexually_active
9: sexual_debut
10: sexual_debut_age
11: fated_debut
12: first_birth_age
13: n_births
14: n_abortions
15: n_twinbirths
16: months_inactive
17: twin_uid
18: dur_breastfeed_total
19: ti_last_delivery
20: ti_live_birth
21: ti_stillbirth
22: ti_miscarriage
23: ti_abortion
24: personal_fecundity
25: birth_ages
26: stillborn_ages
27: miscarriage_ages
28: abortion_ages
29: partnered
30: partnership_age

Increase the number of women who have education

The change_people_state intervention can be used to change ‘states’ or attributes of women. The states you can change are the same list of target states from above. Let’s see what would hapen if we increase education. In FPsim, education is defined based on an education objective and education attainment. The education objective is given to each woman when she enters the model. During her school age years, she gains one year of educationl attainment each year until she reaches her objective. This trajectory can be interrupted if she experiences a pregnancy during those years.

First, we will identify our eligible subpopulation for this intervention. In this case, we are selecting all women who have a goal to achieve at least one year of education.

def select_undereducated(sim):
    """ Select women who have a goal to achieve at least 1 year of education """
    is_eligible = ((sim.people.female) &
                   (sim.people.alive)     & 
                   (sim.people.edu.objective > 0))
    return is_eligible

Now, define a baseline simulation, s0, with no changes.

edu = fp.Education(location=location)
s0 = fp.Sim(pars=pars, education_module=edu, label='Baseline')
Loading data from files in /home/runner/work/fpsim/fpsim/fpsim/locations/kenya/data... 
Applying calibration parameters for kenya...

Next, we define our education change intervention. This intervention finds all of the eligible women (those with a goal of achieveing at least 1 year of education), and gives all of them 15 years of education, starting in the year 2010. We define a simulation, s1, with this educaiton intervention.

change_education = fp.change_people_state(
                        'edu.attainment',
                        eligibility=select_undereducated,
                        years=2010.0,
                        new_val=15,  # Give all selected women 15 years of education
                    )
edu = fp.Education(location=location)
s1 = fp.Sim(pars=pars, 
            education_module=edu, 
            interventions=change_education,
            label='Increased education')
Loading data from files in /home/runner/work/fpsim/fpsim/fpsim/locations/kenya/data... 
Applying calibration parameters for kenya...

Run a multile simulation run with msim to get the results of both of these simulations.

msim = ss.MultiSim(sims=[s0, s1])
msim.run(parallel=False)
s0, s1 = msim.sims
Initializing sim "Baseline" with 1000 agents
/opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/starsim/time.py:1961: RuntimeWarning: divide by zero encountered in log1p
  self._rate = -np.log1p(-v) # Will raise a NumPy warning if it's an array with 1.0 values
  Running "Baseline": 2000 ( 0/145) (0.00 s)  ———————————————————— 1%
  Running "Baseline": 2001 (12/145) (0.14 s)  •——————————————————— 9%
  Running "Baseline": 2002 (24/145) (0.29 s)  •••————————————————— 17%
  Running "Baseline": 2003 (36/145) (0.44 s)  •••••——————————————— 26%
  Running "Baseline": 2004 (48/145) (0.59 s)  ••••••—————————————— 34%
  Running "Baseline": 2005 (60/145) (0.74 s)  ••••••••———————————— 42%
  Running "Baseline": 2006 (72/145) (0.90 s)  ••••••••••—————————— 50%
  Running "Baseline": 2007 (84/145) (1.06 s)  •••••••••••————————— 59%
  Running "Baseline": 2008 (96/145) (1.22 s)  •••••••••••••——————— 67%
  Running "Baseline": 2009 (108/145) (1.38 s)  •••••••••••••••————— 75%
  Running "Baseline": 2010 (120/145) (1.55 s)  ••••••••••••••••———— 83%
  Running "Baseline": 2011 (132/145) (1.72 s)  ••••••••••••••••••—— 92%
  Running "Baseline": 2012 (144/145) (1.89 s)  •••••••••••••••••••• 100%

Initializing sim "Increased education" with 1000 agents
  Running "Increased education": 2000 ( 0/145) (0.00 s)  ———————————————————— 1%
  Running "Increased education": 2001 (12/145) (0.14 s)  •——————————————————— 9%
  Running "Increased education": 2002 (24/145) (0.28 s)  •••————————————————— 17%
  Running "Increased education": 2003 (36/145) (0.43 s)  •••••——————————————— 26%
  Running "Increased education": 2004 (48/145) (0.59 s)  ••••••—————————————— 34%
  Running "Increased education": 2005 (60/145) (0.75 s)  ••••••••———————————— 42%
  Running "Increased education": 2006 (72/145) (0.90 s)  ••••••••••—————————— 50%
  Running "Increased education": 2007 (84/145) (1.06 s)  •••••••••••————————— 59%
  Running "Increased education": 2008 (96/145) (1.23 s)  •••••••••••••——————— 67%
  Running "Increased education": 2009 (108/145) (1.39 s)  •••••••••••••••————— 75%
  Running "Increased education": 2010 (120/145) (1.56 s)  ••••••••••••••••———— 83%
  Running "Increased education": 2011 (132/145) (1.73 s)  ••••••••••••••••••—— 92%
  Running "Increased education": 2012 (144/145) (1.90 s)  •••••••••••••••••••• 100%

Plot the resulting education levels.

plt.plot(s0.results.timevec, s0.results.edu.mean_attainment, label=s0.label)
plt.plot(s1.results.timevec, s1.results.edu.mean_attainment, label=s1.label)
plt.ylabel('Average years of education among women')
plt.xlabel('Year')
plt.legend()