AIDS Mortality example

This notebook illustrates an example present in the Simpact Cyan documentation. There, it is explained that upon infection with HIV the survival time is calculated as $$ t_{\rm survival} = \frac{C}{V_{\rm sp}^{-k}} $$ Because of the start of antiretroviral treatment, or because of dropping out of treatment, the set-point viral load $V_{\rm sp}$ of a person can go down or up again, and the simulations below show what happens to the AIDS based time of death.

This is a very artificial example, meant to illustrate the reasoning in the reference documentation


In [1]:
# First, we'll load the Python interface to Simpact Cyan, as well as the 'math' library
import pysimpactcyan
import math

In [2]:
# Create an instance of the PySimpactCyan class, with which we can run Simpact Cyan simulations
simpact = pysimpactcyan.PySimpactCyan()


Setting data directory to /usr/local/share/simpact-cyan/

In the example from the documentation, survival times of 10 or 50 years are used, depending on treatment. The function below calculates which viral load corresponds to this for a fixed value of $C$ and $k$: $$V_{\rm sp} = \left(\frac{C}{t}\right)^\left(-\frac{1}{k}\right) $$


In [3]:
def solveForVsp(t, C, k):
    return (float(C)/t)**(-1.0/k)

We then set some values for $C$ and $k$, set the time to live before treatment to 10 years, the time to live because of treatment to 50 years, and we calculate the corresponding $V_{\rm sp}$ values


In [4]:
t_before = 10.0
t_after = 50.0
C = 1000
k = -0.5
Vsp_before = solveForVsp(t_before, C, k)
Vsp_after = solveForVsp(t_after, C, k);

Infection only

For the first simulation we'll infect a population consisting of a single person when the simulation starts. We'll make sure that treatment is not used, so if everything works correctly, the person should die at a simulation time of 10 years.


In [5]:
cfg = { 
    # To focus on the AIDS mortality event we'll just use a population that consists
    # of one man
    "population.nummen": 1,
    "population.numwomen": 0,
    # By default, at the start of the simulation a number of people will be infected
    # with HIV. We set the fraction to 100%, so that the only member of our population
    # will certainly get infected when the simulation starts.
    "hivseed.fraction": 1,
    # By setting the age scale for the normal (non-AIDS) mortality event to something
    # very large and by setting the simulation time to something large as well, we can
    # be sure that the simulation will only stop when the one person in it dies from
    # AIDS
    "mortality.normal.weibull.scale": 1000, 
    "population.simtime": 1000,
    # Here, we set the values of the C and k parameters that we defined earlier
    "mortality.aids.survtime.C": C,
    "mortality.aids.survtime.k": k,
    # To make sure that upon infection the person gets the value of Vsp that we want,
    # we use the 'usealternativeseeddist' setting which can be used to specify a distribution
    # for Vsp that can is used when seeding. This distribution should provide the Vsp value
    # on a log10 scale. Since we want one specific value, we'll use the 'fixed' distribution.
    "person.vsp.model.logdist2d.usealternativeseeddist": "yes",
    "person.vsp.model.logdist2d.alternativeseed.dist.type": "fixed",
    "person.vsp.model.logdist2d.alternativeseed.dist.fixed.value": math.log10(Vsp_before),
    
    # Because we don't want treatment in this example, we could in principle just give
    # the diagnosis event a very low hazard. But to make it easier for the following
    # examples we'll actually use a very high hazard for diagnosis so it will happen
    # very shortly after infection
    "diagnosis.baseline": 100,
    # To make sure that no treatment is performed, we'll set the threshold for treatment
    # to zero
    "monitoring.cd4.threshold": 0,
    # On the other hand, thinking ahead again, when a person does get offered treatment
    # we'd like to make sure that he accepts it. This is done by setting the ART
    # accept threshold to 100%, using a 'fixed' distribution again.
    "person.art.accept.threshold.dist.type": "fixed",
    "person.art.accept.threshold.dist.fixed.value": 1,
    # Here we set the interval for the monitoring event to one year.
    "monitoring.interval.piecewise.left": 1,
    "monitoring.interval.piecewise.right": 1,
    "monitoring.interval.piecewise.cd4s": 500,
    "monitoring.interval.piecewise.times": 1,
    # When a monitoring event is triggered and the person's CD4 count is below the
    # threshold, he will be offered treatment. We've already made sure that the person
    # will accept the treatment, and here we specify that treatment should alter the
    # Vsp value to Vsp_after. This is not actually used in this first example, but
    # will be in the next two.
    "monitoring.fraction.log_viralload": math.log10(Vsp_after)/math.log10(Vsp_before),
}

In [7]:
# Now we'll execute the Simpact Cyan simulation with these settings. The `run` function returns
# an object which contains paths to the output files.
r = simpact.run(cfg, "/tmp/simptest")
r


Using identifier 'simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-'
Results will be stored in directory '/tmp/simptest'
Running simpact executable...
Done.

# read seed from /dev/urandom
# Using seed 127474114
# Performing extra check on read configuration parameters
# WARNING: ignoring consistency check for config key population.agedistfile (config value is '/usr/local/share/simpact-cyan/sa_2003.csv')
# mNRM: using advanced algorithm
# Release version
# Simpact version is: 0.18.0
# Error running simulation: No next scheduled event found: No event found
# Current simulation time is 10
# Number of events executed is 16
# Started with 1 people, ending with 0 (difference is -1)
Out[7]:
{'agedistfile': u'/usr/local/share/simpact-cyan/sa_2003.csv',
 'configfile': '/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-config.txt',
 'id': 'simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-',
 u'logevents': u'/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-eventlog.csv',
 u'logperiodic': u'/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-periodiclog.csv',
 u'logpersons': u'/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-personlog.csv',
 u'logrelations': u'/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-relationlog.csv',
 u'logtreatments': u'/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-treatmentlog.csv',
 'outputfile': '/tmp/simptest/simpact-cyan-2015-05-27-09-57-55_27582_MI9gYIY1-output.txt'}

In [8]:
# We'll display the log of all events which is stored in the file specified by `logevents`.
print(open(r["logevents"]).read())


0.0000000000,HIV seeding,(none),-1,-1,-1.0000000000,(none),-1,-1,-1.0000000000
0.0000000000,diagnosis,man_1,1,0,42.2343919168,(none),-1,-1,-1.0000000000
0.0000436102,monitoring,man_1,1,0,42.2344355270,(none),-1,-1,-1.0000000000,CD4,1223.91
0.2518972274,chronicstage,man_1,1,0,42.4862891441,(none),-1,-1,-1.0000000000
1.0000436102,monitoring,man_1,1,0,43.2344355270,(none),-1,-1,-1.0000000000,CD4,1101.56
2.0000436102,monitoring,man_1,1,0,44.2344355270,(none),-1,-1,-1.0000000000,CD4,979.218
3.0000436102,monitoring,man_1,1,0,45.2344355270,(none),-1,-1,-1.0000000000,CD4,856.872
4.0000436102,monitoring,man_1,1,0,46.2344355270,(none),-1,-1,-1.0000000000,CD4,734.527
5.0000436102,monitoring,man_1,1,0,47.2344355270,(none),-1,-1,-1.0000000000,CD4,612.181
6.0000436102,monitoring,man_1,1,0,48.2344355270,(none),-1,-1,-1.0000000000,CD4,489.835
7.0000436102,monitoring,man_1,1,0,49.2344355270,(none),-1,-1,-1.0000000000,CD4,367.489
8.0000436102,monitoring,man_1,1,0,50.2344355270,(none),-1,-1,-1.0000000000,CD4,245.143
8.7500000000,aidsstage,man_1,1,0,50.9843919168,(none),-1,-1,-1.0000000000
9.0000436102,monitoring,man_1,1,0,51.2344355270,(none),-1,-1,-1.0000000000,CD4,122.797
9.5000000000,finalaidsstage,man_1,1,0,51.7343919168,(none),-1,-1,-1.0000000000
10.0000000000,aidsmortality,man_1,1,0,52.2343919168,(none),-1,-1,-1.0000000000,intreatment,0

Each line starts with the time an event took place, followed by the name of the event and some additional information. An overview:

  • At the start of the simulation, the HIV seeding event is executed which causes the only person in the population to get infected.
  • Because of the high baseline value for the diagnosis hazard, this man will get diagnosed immediately afterwards. At this point, a monitoring event is also scheduled a very short time later.
  • When the monitoring event is triggered, no treatment will be offered because we set the CD4 threshold to a very low value. But we keep track of the disease progression by scheduling monitoring events on a yearly basis.
  • Slightly later than three months after the infection (some randomness is added), the chronic stage event will take place.
  • One year and three months before the AIDS based time of death, the person advances to the AIDS stage, and six months before the AIDS related death to the final AIDS stage.
  • Finally, 10 years after the infection was started, the person dies from AIDS

Treatment

In the second example, we'll make sure the person is treated after one year. To do so, we make use of the simulation intervention, by which we can change parameters of the previous simulation at certain times.

In the previous simulation, no treatment occurred because the CD4 threshold was set to zero. To make sure that the person will get treated during the monitoring event that occurs after the first simulation year has passed, we'll trigger a simulation intervention just before that time and set the CD4 threshold to a very high value (so the person's CD4 will be below that value)


In [9]:
intCfg = {
    # This change in configuration will take place one year into the simulation
    "time": 0.99, 
    # At that time the CD4 threshold is set to a very large value, so that during
    # the next monitoring event the person will receive treatment
    "monitoring.cd4.threshold": 100000,
    # We're not interested in any more monitoring events, so we'll set the interval
    # to 1000 years
    "monitoring.interval.piecewise.left": 1000,
    "monitoring.interval.piecewise.right": 1000,
    "monitoring.interval.piecewise.times": 1000,
    # In this example we do not want the person to drop out of treatment, so the
    # dropout interval is set to the fixed value of 1000 years
    "dropout.interval.dist.type": "fixed",
    "dropout.interval.dist.fixed.value": 1000,
}

# Then we run the simulation with the existing configuration and with the intervention
# configuration above
r = simpact.run(cfg, "/tmp/simptest", interventionConfig=[intCfg])


Using identifier 'simpact-cyan-2015-05-27-09-57-58_27582_w3jF9ObQ-'
Results will be stored in directory '/tmp/simptest'
Running simpact executable...
Done.

# read seed from /dev/urandom
# Using seed 743695429
# Performing extra check on read configuration parameters
# WARNING: ignoring consistency check for config key intervention.baseconfigname (config value is 'simpact-cyan-2015-05-27-09-57-58_27582_w3jF9ObQ-interventionconfig_%.txt')
# WARNING: ignoring consistency check for config key intervention.fileids (config value is '1')
# WARNING: ignoring consistency check for config key population.agedistfile (config value is '/usr/local/share/simpact-cyan/sa_2003.csv')
# mNRM: using advanced algorithm
# Release version
# Simpact version is: 0.18.0
# Error running simulation: No next scheduled event found: No event found
# Current simulation time is 46
# Number of events executed is 9
# Started with 1 people, ending with 0 (difference is -1)

In [10]:
# Let's show the event log again
print open(r["logevents"]).read()


0.0000000000,HIV seeding,(none),-1,-1,-1.0000000000,(none),-1,-1,-1.0000000000
0.0000000000,diagnosis,man_1,1,0,29.8100951390,(none),-1,-1,-1.0000000000
0.0000065722,monitoring,man_1,1,0,29.8101017112,(none),-1,-1,-1.0000000000,CD4,1080.9
0.2519573432,chronicstage,man_1,1,0,30.0620524822,(none),-1,-1,-1.0000000000
0.9900000000,intervention,(none),-1,-1,-1.0000000000,(none),-1,-1,-1.0000000000
1.0000065722,monitoring,man_1,1,0,30.8101017112,(none),-1,-1,-1.0000000000,CD4,982.282
1.0000065722,(treatment),man_1,1,0,30.8101017112,(none),-1,-1,-1.0000000000
44.7499737111,aidsstage,man_1,1,0,74.5600688501,(none),-1,-1,-1.0000000000
45.4999737111,finalaidsstage,man_1,1,0,75.3100688501,(none),-1,-1,-1.0000000000
45.9999737111,aidsmortality,man_1,1,0,75.8100688501,(none),-1,-1,-1.0000000000,intreatment,1

When the monitoring event is triggered at the simulation time of one year, the CD4 count is now below the (very high) threshold that we installed in the simulation intervention that happened right before. This causes the man to receive treatment, which in turn lowers his Vsp value.

As you can see, because of this the man now continues to live for 45 more years. Also note that again one year and three months before dying, the AIDS stage event is triggered, and six months before dying, the final AIDS stage.

Treatment and dropout

This final simulation corresponds to the example that was given in the documentation. As in the previous one, the person will get treated after one year, but now he will drop out of treatment ten years later again.


In [11]:
intCfg = { 
    # This change in configuration will take place one year into the simulation
    "time": 0.99,
    # At that time the CD4 threshold is set to a very large value, so that during
    # the next monitoring event the person will receive treatment
    "monitoring.cd4.threshold": 100000,
    # To make sure that the person drops out of treatment 10 years later, we 
    # fix this value
    "dropout.interval.dist.type": "fixed",
    "dropout.interval.dist.fixed.value": 10,
    # To prevent a person from being re-diagnoses after dropout, we'll set the
    # baselline value for this hazard to a very negative value (causes a very low
    # hazard)
    "diagnosis.baseline": -100,
    # We're not interested in any more monitoring events, so we'll set the interval
    # to 1000 years
    "monitoring.interval.piecewise.left": 1000,
    "monitoring.interval.piecewise.right": 1000,
    "monitoring.interval.piecewise.times": 1000,
}

r = simpact.run(cfg, "/tmp/simptest", interventionConfig=[intCfg])


Using identifier 'simpact-cyan-2015-05-27-09-58-01_27582_HPt1Qo6a-'
Results will be stored in directory '/tmp/simptest'
Running simpact executable...
Done.

# read seed from /dev/urandom
# Using seed 513573549
# Performing extra check on read configuration parameters
# WARNING: ignoring consistency check for config key intervention.baseconfigname (config value is 'simpact-cyan-2015-05-27-09-58-01_27582_HPt1Qo6a-interventionconfig_%.txt')
# WARNING: ignoring consistency check for config key intervention.fileids (config value is '1')
# WARNING: ignoring consistency check for config key population.agedistfile (config value is '/usr/local/share/simpact-cyan/sa_2003.csv')
# mNRM: using advanced algorithm
# Release version
# Simpact version is: 0.18.0
# Error running simulation: No next scheduled event found: No event found
# Current simulation time is 18
# Number of events executed is 10
# Started with 1 people, ending with 0 (difference is -1)

In [12]:
# Let's show the event log again
print open(r["logevents"]).read()


0.0000000000,HIV seeding,(none),-1,-1,-1.0000000000,(none),-1,-1,-1.0000000000
0.0000000000,diagnosis,man_1,1,0,32.8931507538,(none),-1,-1,-1.0000000000
0.0000075811,monitoring,man_1,1,0,32.8931583349,(none),-1,-1,-1.0000000000,CD4,1102.89
0.2521192669,chronicstage,man_1,1,0,33.1452700207,(none),-1,-1,-1.0000000000
0.9900000000,intervention,(none),-1,-1,-1.0000000000,(none),-1,-1,-1.0000000000
1.0000075811,monitoring,man_1,1,0,33.8931583349,(none),-1,-1,-1.0000000000,CD4,1002.41
1.0000075811,(treatment),man_1,1,0,33.8931583349,(none),-1,-1,-1.0000000000
11.0000075811,dropout,man_1,1,0,43.8931583349,(none),-1,-1,-1.0000000000
16.7500000000,aidsstage,man_1,1,0,49.6431507538,(none),-1,-1,-1.0000000000
17.5000000000,finalaidsstage,man_1,1,0,50.3931507538,(none),-1,-1,-1.0000000000
18.0000000000,aidsmortality,man_1,1,0,50.8931507538,(none),-1,-1,-1.0000000000,intreatment,0

The start of the simulation is the same as before and one year after getting infected, the man receives treatment. But now, ten years after that time, the man decides to drop out of treatment which causes his $V_{\rm sp}$ value to go up again. Instead of living for tens of years afterwards, after dropping out only seven more years remain until the person dies of AIDS.