Skip to content

Modeling (Non‐Disease) Mortality

Jonathan Bloedow edited this page Jul 11, 2024 · 7 revisions

Abstract

In the laser-jb prototype, natural (non-disease) mortality is modeled as follows:

  1. EULA mortality is done using the precalculated fitted curves for the declining population of each node over time.

  2. The modeled population mortality is done by excluding from all the counts anyone with an age > expected_lifespan. expected_lifespan is set during initialization. The formulae for these are intended to be placeholder math that's "the simplest way of doing something not entirely unplausible" with the expectation that you'd replace with something more sophisticated and suitable to the modeled setting.

Note that this highly optimized-for-speed approach doesn't enable a nice real-time reporting of "how many people died this timestep".

EULA Mortality

During the setup part of the workflow, which is done once per "setting", the EULA fraction of the population is modeled once in the sense of aging and dying using the Gompertz-Makeham law and parameters 0.008 (Makeham) and 0.04 (Gomphertz).

From this, the declining EULA population of each node is recorded at each timestep. These population curves are then fitted using a simple linear regression. From all these we save a file fits.npy which has the slope and intercept of the fit line for each node. This lets us retrieve approximated populations of the EULA population over time very efficiently.

Note that you are of course free to change the code and use other lifespan approximations or data. This is just supposed to be a lightweight approach that is not unreasonable. You can also use higher order polynomial fits to the curve. This general approach is obviously quite aggressive from a performance point of view. The main insight here is that EULA population over time and place almost certainly doesn't need to be remodeled each time we run the disease model so we can "pre-run" it once, massively compress the essential output, and efficiently interpolate population values from that during disease modeling runs.

Modeled Population

In the current prototype, our modeled population dataframe has an "expected_lifespan" column and we determine if someone is dead or alive based on whether their current age is greater or less than their expected_lifespan. You can populate expected_lifespan from whatever population model or dataset you want. In the code right now, it's done from a beta distribution. Note that this is done for both the initial population input dataframe as well as the newborns.

The eagle-eyed will notice that the get_beta_samples function is essentially duplicated in a couple of places. That will be fixed soon.

The age-at-death distribution from the current code and parameters looks like:

Screenshot from 2024-07-08 17-29-09

Notes

  • We have talked about having a one-time calculation of death and setting a bit/flag. I personally haven't attempted that or checked if it's more efficient.

  • The current code doesn't always check if a modeled population agent is still alive in various "step functions". Sometimes that's not an error because, for example, increasing ages for "dead" people each timestep might be more performant than checking each agent first to see if their age is < their expected_lifespan. It's still possible that having an "active" flag that is set once and checked in each step function is more efficient, but at this point I doubt it. But it's certainly possible that there is a step function that does incorrectly operate on effectively dead agents. (Update: after review, my current code is selecting susceptible agents for infection without regard to their mortality status, so we're probably getting some bogus infectees. Need to fix. There's also some campaign code, not currently in use, that will need to be updated to be mortality-aware.)

  • The current code doesn't do any "swapping" anymore, so dead people are not swapped out over the Active Agent Event Horizon. The latest data shows that it's more efficient to leave them in place and ignore them when necessary.