starsimhub / starsim

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

Distribution parsing #331

Closed cliffckerr closed 7 months ago

cliffckerr commented 7 months ago

Modules parse the pars dict and anything that is an rv_frozen object gets converted to a ScipyDistribution instead. However, this only works for things in the top-level of pars, and doesn't work for other things (e.g., if you want to get random numbers in an intervention). For example:

import sciris as sc
import starsim as ss

class CallDist(ss.Intervention):

    def __init__(self):
        super().__init__()
        self.dists = [ss.lognorm, ss.norm]

    def apply(self, sim):
        rvs1 = self.dists[0].rvs(1, size=2)
        rvs2 = sim.diseases.sir.pars.nested.dist.rvs(1, size=2)
        print(f't={sim.ti}, values={rvs1}, and {rvs2}')

disease = ss.SIR(pars=dict(
    dur_inf = 10,
    beta = 0.1,
    nested = sc.objdict(dist = ss.lognorm),
))

sim = ss.Sim(pars=dict(networks='random'), diseases=disease, interventions=CallDist())
sim.run()

sc.heading('Types')
print(type(sim.diseases.sir.pars.dur_inf))
print(type(sim.diseases.sir.pars.nested.dist))
print(type(sim.interventions[0].dists[0]))

I'd prefer if ss.lognorm etc. threw an error if not initialized with a sim. I can't think of a case where this isn't an error. Otherwise, people can just use sps.lognorm.

daniel-klein commented 7 months ago

Seems like a nicer way to wrap the ScipyDistribution, and we could add checks for initialization and maybe also .ready. Wondering if we have to wrap each distribution individually or if we'll go down the __getattr__ route as with the previous numpy-based approach? Also, doing so would solidify the disconnection to Scipy's documentation, which feels like a significant tradeoff.

cliffckerr commented 7 months ago

Closed by #392