starsimhub / starsim

Starsim disease modeling framework
http://starsim.org
MIT License
14 stars 8 forks source link

Rethink time #326

Closed cliffckerr closed 2 weeks ago

cliffckerr commented 7 months ago

We need to solve how we handle time. I was thinking is that each module could have a time unit defined, which at least initially we could restrict to 'day' or 'year'. Then all parameter values defined in that module would be relative to that module's time unit. (If unit='day', then start and end would be dates; if unit='year', they would be ints/floats, although dates would also work. I was also thinking of a 'none' option, which would just use the timesteps directly.)

It would be nice if we had very simple ss.dur and ss.rate classes, which are time-unit aware. This would save the user the trouble of remembering to divide/multiply by the correct dt everywhere. The user wouldn't have to see these; they'd be implemented in the default parameters and merged with user-supplied parameters. So the default for SIR would be pars.dur_inf = ss.dur(6), but the user could just supply diseases=dict(type='sir', dur_inf=6) and it would get converted a dur based on the default (this is related to the sim API work).

The part I really struggled with was how to do the actual integration in sim.step(). Should the sim timestep be the smallest of the module timesteps, such that on each sim timestep, each module either runs or is pass? Or should the sim timestep equal the results timestep, which may or may not correspond to any individual module timestep? And how do we nicely handle results when everything is happening at different times? My best idea was something like this:

def sim.step():
  sim.now += sim.dt
  for module in modules:
    module.step(sim)

def module.step(sim):
  while self.now < sim.now:
    self.now += self.dt
    [do stuff]

Some open questions:

kaa2102 commented 7 months ago

This topic came up on yesterday's RSV call. Should we enable and distinguish between both (1) modeling parameter inputs sim_time_unit_steps=1 #days and (2) results display sim_time_display_units=365 #days?

daniel-klein commented 7 months ago

Yes, love this one. Question: how would this switch work without each parameter explicitly having associated units? (Or maybe that's part of the solution?)

cliffckerr commented 6 months ago

I suggest (responding also to #418) something like:

# Sim in years
s1 = ss.Sim(start=1990, end=2040, dt=0.1, unit='year', diseases='hiv')

# Sim in days
s2 = ss.Sim(start='2025-01-01', end='2025-07-01', dt=7, unit='day', diseases='rsv')

We could probably by default interpret an integer start and end as implying years, and a string or datetime as implying days. For units of days, we should be able to borrow Covasim's logic for handling everything.

cliffckerr commented 6 months ago

Can also make the default start 0, to be agnostic about whether it's a day, year, or just timestep!

cliffckerr commented 2 weeks ago

Closed by #623