-
Notifications
You must be signed in to change notification settings - Fork 5
Modeling (Non‐Disease) Mortality ‐‐ An Overview of Options
Because LASER is so flexible, it doesn't dictate to the end user how to model things like natural mortality, except to say that you should not remove dead agents from the main memory space as they die, and you should not do things which are slow. Within those parameters, there are numerous options and it's worth noting what they are, and showing how LASER can support them. This is a good list from ChatGPT.
Here's a comprehensive list of distinct ways to model mortality in your agent-based simulation using properties like age or date of birth, along with a Kaplan-Meier estimator for assigning lifespans:
Attributes: age, lifespan
Mechanism: Each agent is assigned an initial age and a lifespan based on the Kaplan-Meier estimator. Mortality is checked by comparing age to lifespan at each timestep. One can optionally set an "active" or "alive" type boolean flag which can be checked by other components, or one can just keep comparing age with lifespan where components care. If one wants to keep a count of new deaths, one probably needs to flip an alive bit upon death. Note that the aging and killing components are probably best merged into one.
Pros: Simple and intuitive.
Cons: Requires updating age every timestep.
Conclusion: This is basically Jonathan's default approach.
Attributes: date_of_birth, lifespan
Mechanism: Each agent is assigned a date_of_birth (based on simulation start time) and a lifespan. Death occurs when the simulation tick reaches date_of_birth + lifespan.
Pros: Avoids explicitly storing age; uses ticks directly.
Cons: Requires recalculating current_age when needed.
Attributes: time_to_death
Mechanism: Assign each agent a time_to_death at initialization, calculated from Kaplan-Meier. Agents are added to a priority queue sorted by time_to_death. Check the queue each timestep to handle deaths.
Pros: Efficient for large populations; minimizes per-agent updates.
Cons: Adds overhead for maintaining a priority queue.
Conclusion: This is basically the built-in laser-measles approach.
Attributes: age, lifespan
Mechanism: Each agent has an age and lifespan. Upon initialization, schedule a "death event" in a global event queue for current_tick + (lifespan - age). Deaths are processed when their event triggers.
Pros: Combines age tracking and event scheduling; efficient for sparsely occurring deaths.
Cons: Requires maintaining a global event queue.
Conclusion: This seems similar to #3 but less efficient. No plans to consider this.
Attributes: age, mortality_rate
Mechanism: Assign a mortality_rate based on age (using Kaplan-Meier survival probabilities). At each timestep, roll a random number to determine if the agent dies.
Pros: Allows dynamic mortality rates that change with age or environment.
Cons: Stochastic, which can lead to variability in results.
Conclusion: This is basically what EMOD historically does.
Attributes: age, lifespan--
Mechanism: Precompute a survival table for the population, mapping each age to a Kaplan-Meier-derived probability. Assign each agent a lifespan based on the table. Death occurs when age exceeds lifespan.
Pros: Simplifies lifespan assignment; avoids per-agent Kaplan-Meier computation.
Cons: Requires sufficient memory for the table.
Conclusion: I don't really see the case for this.
Attributes: remaining_lifespan
Mechanism: Assign each agent an initial remaining_lifespan based on Kaplan-Meier. Decrease remaining_lifespan by one each timestep. Death occurs when it reaches zero.
Pros: Straightforward implementation; avoids recalculating age. Countdown timers are a staple of LASER.
Cons: Requires updating this property for every agent every timestep.
Conclusion: I consider this a variation on #3 and a very LASER-ish option. If the end-user is comfortable with PriorityQueues, go with #3. If the user just wants countdown timers, this approach is very simple. And the user can then choose whether to do this every timestep, or at a courser granularity, like every 30 days, which is nearly always fine for mortality.
Attributes: age, hazard_rate
Mechanism: Assign a dynamic hazard_rate to each agent based on Kaplan-Meier. At each timestep, roll a random number to see if the agent dies (probability proportional to the hazard rate).
Pros: Allows mortality to be influenced by changing factors.
Cons: Computationally intensive for large populations.
Conclusion: Very unlikely that we'll want this for a LASER solution, which is "light agent" and needs to be fast for very large populations.
Attributes: expected_death_date
Mechanism: Precompute an expected_death_date for each agent based on Kaplan-Meier and their date_of_birth. Death occurs when the simulation tick reaches the expected_death_date.
Pros: Avoids explicit age tracking; ties mortality directly to simulation ticks.
Cons: Assumes a deterministic lifespan, which may not capture stochastic variability.
Attributes: lifespan_bucket, age
Mechanism: Divide agents into lifespan buckets (e.g., 0-10 years, 10-20 years) based on Kaplan-Meier. At each timestep, check if an agent's bucket is expired based on their age.
Pros: Simplifies processing for groups of agents with similar lifespans.
Cons: Reduces granularity in lifespan modeling.
Attributes: age, alive
Mechanism: Assign each agent a survival curve based on Kaplan-Meier. At each timestep, use the curve to determine the probability that the agent survives to the next timestep.
Pros: Flexible and accurate; dynamically adapts to changing survival probabilities.
Cons: Computationally expensive for large populations. Thus not suitable for LASER.
Attributes: age, lifespan
Mechanism: Start each agent at death and simulate backward to birth, assigning a lifespan post hoc based on Kaplan-Meier. Adjust the simulation timeline accordingly. This seems similar to the idea of "simulate vital dynamics separately first and reuse in epi sims" idea.
Pros: Ensures equilibrium in mortality.
Cons: Unorthodox and may require significant rethinking of simulation logic.
Attributes: cohort_age, cohort_size
Mechanism: Group agents by cohorts (e.g., age bins). Assign each cohort an aggregated mortality rate based on Kaplan-Meier. Deaths occur at the cohort level rather than the individual level.
Pros: Simplifies large-scale simulations.
Cons: Loses individual-level resolution.
Attributes: base_lifespan, adjusted_lifespan
Mechanism: Assign each agent a base_lifespan from Kaplan-Meier and dynamically adjust it based on external factors (e.g., disease, accidents). Death occurs when age exceeds adjusted_lifespan.
Pros: Incorporates dynamic, external influences on mortality.
Cons: Complex to implement.
Each method has trade-offs depending on the complexity of your model, the desired realism, and computational efficiency. Let me know if you'd like me to elaborate on implementing any of these!