starsimhub / starsim

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

States with ss.Dist are not initialized correctly #533

Closed daniel-klein closed 4 months ago

daniel-klein commented 4 months ago

In TBsim, the TB disease module has a FloatArr that is initialized from a random Dist:

ss.FloatArr('ppf_LS_to_presymp', default=ss.random())

However, every time I run the code, values for ppf_LS_to_presymp are different. Results are not reproducible, even with the same seed.

Could be due to recent changes to initialization, but the feels like a real issue. We need a test for this as well.

cliffckerr commented 4 months ago

Ah, I found the issue -- this distribution gets found first in People.states, where it is given a key based on the object ID, which is effectively random each time:

import starsim as ss

class RandState(ss.Disease):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.add_states(
            ss.FloatArr('test_state', default=ss.random())
        )

    def init_post(self):
        super().init_post()
        print('Initial value', self.test_state[0])

sim = ss.Sim(diseases=RandState(), networks='random')
sim.run()

#0. 'pars_randomnet_n_contacts': # fine
ss.constant(pars_randomnet_n_contacts, pars={'v': 10})
#1. 'people_female_default': # fine
ss.bernoulli(people_female_default, pars={'p': 0.5})
#2. 'people_age_default': # fine
ss.uniform(people_age_default, pars={'low': 0, 'high': 100})
#3. 'networks_randomnet_dist': # fine
ss.Dist(networks_randomnet_dist, dist=RandomNet, pars={})
#4. 'people__states_136907923215568_default': # NOT FINE
ss.random(people__states_136907923215568_default, pars={})

I think the best solution is to just skip People.states when parsing the object for dists to find, but will need to think if this would have unexpected consequences.