optimamodel / optima-tb

Optima TB-UCL model
GNU Lesser General Public License v3.0
2 stars 0 forks source link

Simplified negative pops #109

Closed RomeshA closed 6 years ago

RomeshA commented 6 years ago

Averting negative populations in the model can fail under certain circumstances, because people are allowed to skip compartments in a single timestep. That is, inflow to a population can be used to supply people for an outflow to prevent a compartment becoming negative. The changes in this PR enforce that a person must spend at least one timestep in a compartment, so only people who are in the compartment at the start of the timestep are able to leave it. This simplifies ensuring that the compartment size does not become negative. In tests with Belarus and South Africa, differences in the population sizes were negligible so this change is not expected to have significant consequences on existing results, except if an edge case was previously encountered.

Note that because validation is now built into stepForward it is currently not possible to ignore negative populations. The rationale is that since negative population sizes are expected to break validity of results in many places, it should not be possible for a user to accidentally encounter them.

Example below - results should be very similar in develop and in this branch

from optima_tb.project import Project
from optima_tb.utils import odict
from optima_tb.plotting import plotResult

cascade = '../tb-ucl-analyses/belarus/Cascade Spreadsheets/cascade-belarus.xlsx'
databook = '../tb-ucl-analyses/belarus/Databook Spreadsheets/databook-belarus.xlsx'
proj = Project(name='belarus', cascade_path=cascade,validation_level = 'avert')
proj.settings.tvec_start = 2000
proj.settings.tvec_end = 2020
proj.loadSpreadsheet(databook_path=databook)
proj.makeParset()
p = proj.parsets[0].getPar('doth_rate');
for pop in p.y.keys():
    print pop
    proj.parsets[0].getPar('doth_rate').y_format[pop] = 'number'
    proj.parsets[0].getPar('doth_rate').y[pop].fill(1e5) # Make death rate very high
results = proj.runSim(parset_name='default',plot=False) # Need to uncommment import statement in project.py for this to run in develop branch
import matplotlib.pyplot as plt
figs=plotResult(proj,results,['alive'],plot_total=False)
plt.show()
RomeshA commented 6 years ago

over-saturated outflows can draw from inflows before being truncated by checkNegativePopulation() in model.py