def apply(self, pop, group, iter, t): p = self.p_infection_min if group.has_rel({ Site.AT: group.get_rel('school') }): site = group.get_rel(Site.AT) na = site.get_pop_size(GroupQry(attr={ 'flu': 'i' })) ns = site.get_pop_size(GroupQry(attr={ 'flu': 'r' })) p = self.get_p_infection_site(na, ns) if group.get_attr('flu') == 's': return [ GroupSplitSpec(p=1 - p, attr_set={ 'flu': 's' }), GroupSplitSpec(p=p, attr_set={ 'flu': 'i' }) ] elif group.get_attr('flu') == 'i': return [ GroupSplitSpec(p=0.50, attr_set={ 'flu': 'i' }), GroupSplitSpec(p=0.50, attr_set={ 'flu': 's' }) ] elif group.get_attr('flu') == 'r': return [ GroupSplitSpec(p=0.10, attr_set={ 'flu': 's' }), GroupSplitSpec(p=0.90, attr_set={ 'flu': 'r' }) ] else: raise ValueError("Invalid value for attribute 'flu'")
def apply(self, pop, group, iter, t): if group.has_attr({ 'flu': 's' }): at = group.get_rel(Site.AT) n = at.get_pop_size() n_s = at.get_pop_size(GroupQry(attr={ 'flu': 's' })) n_e = at.get_pop_size(GroupQry(attr={ 'flu': 'e' })) n_i = at.get_pop_size(GroupQry(attr={ 'flu': 'i' })) beta = R0 / (population*infectiousPeriod) lambdat = beta*n_i fractionInfected = float(n_i) / float(n) numberOfNewlyInfected = np.random.binomial(n_s,lambdat) p_infection = float(numberOfNewlyInfected+n_e)/float(n) return [ GroupSplitSpec(p=p_infection, attr_set={ 'flu': 'e' }), GroupSplitSpec(p=1-p_infection, attr_set={ 'flu': 's' }) ] if group.has_attr({ 'flu': 'e' }): p_transition = 1.0/latentPeriod return [ GroupSplitSpec(p=p_transition, attr_set={ 'flu': 'i' }), GroupSplitSpec(p=1.0-p_transition, attr_set={ 'flu': 'e' }) ] if group.has_attr({ 'flu': 'i' }): at = group.get_rel(Site.AT) n_i = at.get_pop_size(GroupQry(attr={ 'flu': 'i' })) print( n_i, end=' ' ) p_transition = 1.0/infectiousPeriod return [ GroupSplitSpec(p=p_transition, attr_set={ 'flu': 'r' }), GroupSplitSpec(p=1.0-p_transition, attr_set={ 'flu': 'i' }) ]
def apply(self, pop, group, iter, t): mouse_group = pop.get_group(GroupQry({'form': "m"})) mouse_population = mouse_group.m hawk_group = pop.get_group(GroupQry({'form': 'h'})) hawk_population = hawk_group.m / 5 appetite = mouse_population * hawk_population * PREDATION_COEFFICIENT if group.attr['form'] == 'h': p = PREDATOR_MORTALITY p = p * TIME_COEFFICIENT return [ GroupSplitSpec(p=p, attr_set={'form': "c"}), GroupSplitSpec(p=1 - p) ] elif group.attr['form'] == 'm': if appetite > mouse_population: appetite = mouse_population p = appetite / mouse_population p = p * TIME_COEFFICIENT return [ GroupSplitSpec(p=p, attr_set={'form': "h"}), GroupSplitSpec(p=1 - p) ] else: return [GroupSplitSpec(p=1)]
def get_probe_flu_at(school, name=None): return GroupSizeProbe( name=name or school.name, queries=[ GroupQry(attr={ 'flu': 's' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'i' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'r' }, rel={ 'school': school }) ], qry_tot=GroupQry(rel={ 'school': school }), msg_mode=ProbeMsgMode.DISP )
def probe_flu_at(school, name=None): return GroupSizeProbe( name=name or school.name, queries=[ GroupQry(attr={ 'flu': 's' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'i' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'r' }, rel={ 'school': school }) ], qry_tot=GroupQry(rel={ 'school': school }), persistance=pp, var_names=['ps', 'pi', 'pr', 'ns', 'ni', 'nr'] )
def sim_flu_ac_init_get_probe(school, name=None): return GroupSizeProbe( name=name or str(school.name), queries=[ GroupQry(attr={ 'flu': 's' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'e' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'r' }, rel={ 'school': school }) ], qry_tot=GroupQry(rel={ 'school': school }), persistance=None, # pp, var_names=['ps', 'pe', 'pr', 'ns', 'ne', 'nr'] )
def probe_grp_size_flu_school(name, school, pp): return GroupSizeProbe(name=name, queries=[ GroupQry(attr={'flu': 's'}, rel={'school': school}), GroupQry(attr={'flu': 'e'}, rel={'school': school}), GroupQry(attr={'flu': 'r'}, rel={'school': school}) ], qry_tot=GroupQry(rel={'school': school}), persistence=pp, var_names=['ps', 'pe', 'pr', 'ns', 'ne', 'nr'])
def apply_keep_migrating(self, pop, group, iter, t): migrating_groups = pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'is-migrating': True})])) if migrating_groups and len(migrating_groups) > 0: migrating_m = sum([g.m for g in migrating_groups]) migrating_p = migrating_m / pop.m * 100 else: migrating_p = 0 env_harshness = self.env.get_harshness(iter % 11, True) p_death = min( env_harshness * self.env_harshness_death_mult + migrating_p * self.migration_death_mult, 1.00) time_traveled = 1 if env_harshness <= 0.90 else 0 # no travel in very harsh climate return [ GroupSplitSpec(p=p_death, attr_set=Group.VOID), GroupSplitSpec(p=1 - p_death, attr_set={ 'migration-time': group.get_attr('migration-time') + 1, 'travel-time-left': group.get_attr('travel-time-left') - time_traveled }) ]
def __init__(self, env, env_harshness_death_mult=0.001, migration_death_mult=0.05, name='migration', t=TimeAlways(), i=IterAlways()): super().__init__(name, t, i, group_qry=GroupQry(cond=[lambda g: g.has_attr({ 'is-migrating': True })])) self.env = env self.env_harshness_death_mult = env_harshness_death_mult self.migration_death_mult = migration_death_mult
def apply(self, pop, group, iter, t): # Susceptible: if group.has_attr({ 'flu': 's' }): at = group.get_rel(Site.AT) n = at.get_pop_size() # total population at the group's current location n_i = at.get_pop_size(GroupQry(attr={ 'flu': 'i' })) # infected population at the group's current location p_infection = float(n_i) / float(n) # changes every iteration (i.e., the source of the simulation dynamics) return [ GroupSplitSpec(p= p_infection, attr_set={ 'flu': 'i', 'mood': 'annoyed' }), GroupSplitSpec(p=1 - p_infection, attr_set={ 'flu': 's' }) ] # Infected: if group.has_attr({ 'flu': 'i' }): return [ GroupSplitSpec(p=0.2, attr_set={ 'flu': 'r', 'mood': 'happy' }), GroupSplitSpec(p=0.5, attr_set={ 'flu': 'i', 'mood': 'bored' }), GroupSplitSpec(p=0.3, attr_set={ 'flu': 'i', 'mood': 'annoyed' }) ] # Recovered: if group.has_attr({ 'flu': 'r' }): return [ GroupSplitSpec(p=0.9, attr_set={ 'flu': 'r' }), GroupSplitSpec(p=0.1, attr_set={ 'flu': 's' }) ]
def is_applicable(self, group, iter, t): if group.ga("playable") == "yes": return False if group.ga("flu-status") == "s" and not group.get_mass_at( GroupQry(attr={'flu-status': 'i'})) == 0: return False return super().is_applicable(group, iter, t)
def apply_keep_migrating(self, pop, group, iter, t): migrating_groups = pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'is-migrating': True})])) if migrating_groups and len(migrating_groups) > 0: # most attribute access does not work; relevant methods should be called instead # migrating_m = sum([g.m for g in migrating_groups]) # migrating_p = migrating_m / pop.m * 100 # Note however an inconsistency - getting the mass of each agent will be the square of what we want # migrating_m = sum([g.get_mass() for g in migrating_groups]) migrating_m = len(migrating_groups) migrating_p = migrating_m / pop.get_mass() * 100 else: migrating_p = 0 p_death = min( self.env_harshness * self.env_harshness_death_mult + migrating_p * self.migration_death_mult, 1.00) return [ GroupSplitSpec(p=p_death, attr_set=Group.VOID), GroupSplitSpec(p=1 - p_death, attr_set={ 'migration-time': group.get_attr('migration-time') + 1, 'travel-time-left': group.get_attr('travel-time-left') - 1 }) ]
def run_iter(self, iter, t, traj_id): migrating_groups = self.pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'is-migrating': True})])) if migrating_groups and len(migrating_groups) > 0: migration_time_lst = [ g.get_attr('migration-time') for g in migrating_groups ] migrating_m = sum([g.m for g in migrating_groups]) migrating_p = migrating_m / self.pop.m * 100 migrating_time_mean = statistics.mean(migration_time_lst) migrating_time_sd = statistics.stdev( migration_time_lst) if len(migration_time_lst) > 1 else 0 else: migrating_m = 0 migrating_p = 0 migrating_time_mean = 0 migrating_time_sd = 0 print( f'{iter or 0:>4} ' + f'pop: {self.pop.m:>9,.0f} ' + f'dead: {self.pop.m_out:>9,.0f}|{self.pop.m_out / self.pop_m_init * 100:>3,.0f}% ' + f'migrating: {migrating_m:>9,.0f}|{migrating_p:>3.0f}% ' + f'migration-time: {migrating_time_mean:>6.2f} ({migrating_time_sd:>6.2f})' ) if self.persistence: self.persistence.persist(self, [ self.pop.m, self.pop.m_out, migrating_m, migrating_p, migrating_time_mean, migrating_time_sd ], iter, t, traj_id)
def apply(self, pop, group, iter, t): # Susceptible: if group.has_attr({ 'flu': 's' }): at = group.get_rel(Site.AT) n = at.get_pop_size() # total population at current location n_e = at.get_pop_size(GroupQry(attr={ 'flu': 'e' })) # exposed population at current location p_infection = float(n_e) / float(n) # changes every iteration (i.e., the source of the simulation dynamics) return [ GroupSplitSpec(p= p_infection, attr_set={ 'flu': 'e' }), GroupSplitSpec(p=1 - p_infection, attr_set={ 'flu': 's' }) ] # Exposed: if group.has_attr({ 'flu': 'e' }): return [ GroupSplitSpec(p=0.2, attr_set={ 'flu': 'r' }), GroupSplitSpec(p=0.5, attr_set={ 'flu': 'e' }), GroupSplitSpec(p=0.3, attr_set={ 'flu': 'e' }) ] # Recovered: if group.has_attr({ 'flu': 'r' }): return [ GroupSplitSpec(p=0.9, attr_set={ 'flu': 'r' }), GroupSplitSpec(p=0.1, attr_set={ 'flu': 's' }) ] raise ValueError('Unknown flu state')
def apply(self, pop, group, iter, t): # Susceptible: if group.has_attr({'flu': 's'}): at = group.get_rel(Site.AT) n = at.get_pop_size() # total population at current location n_i = at.get_pop_size(GroupQry( attr={'flu': 'i'})) # infected population at current location p_infection = float(n_i) / float( n ) # changes every iteration (i.e., the source of the simulation dynamics) return [ GroupSplitSpec(p=p_infection, attr_set={'flu': 'i'}), GroupSplitSpec(p=1 - p_infection, attr_set={'flu': 's'}) ] # Infected: if group.has_attr({'flu': 'i'}): return [ GroupSplitSpec(p=0.2, attr_set={ 'flu': 'r' }), # group size after: 20% of before (recovered) GroupSplitSpec(p=0.8, attr_set={ 'flu': 'i' }) # group size after: 80% of before (still infected) ] # Recovered: if group.has_attr({'flu': 'r'}): return [ GroupSplitSpec(p=0.9, attr_set={'flu': 'r'}), GroupSplitSpec(p=0.1, attr_set={'flu': 's'}) ]
def run_iter(self, iter, t, traj_id): # Migrating population: migrating_groups = self.pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'is-migrating': True})])) if migrating_groups and len(migrating_groups) > 0: migration_time_lst = [ g.get_attr('migration-time') for g in migrating_groups ] migrating_m = sum([g.m for g in migrating_groups]) migrating_p = migrating_m / self.pop.m * 100 migrating_time_mean = statistics.mean(migration_time_lst) migrating_time_sd = statistics.stdev( migration_time_lst) if len(migration_time_lst) > 1 else 0 else: migrating_m = 0 migrating_p = 0 migrating_time_mean = 0 migrating_time_sd = 0 # Settled population: settled_groups = self.pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'has-settled': True})])) if settled_groups and len(settled_groups) > 0: settled_m = sum([g.m for g in settled_groups]) settled_p = settled_m / self.pop.m * 100 else: settled_m = 0 settled_p = 0 # Print and persist: print( f'{iter or 0:>4} ' + f'pop: {self.pop.m:>9,.0f} ' + f'dead: {self.pop.m_out:>9,.0f}|{self.pop.m_out / self.pop_m_init * 100:>3,.0f}% ' + f'migrating: {migrating_m:>9,.0f}|{migrating_p:>3.0f}% ' + f'migration-time: {migrating_time_mean:>6.2f} ({migrating_time_sd:>6.2f}) ' + f'settled: {settled_m:>9,.0f}|{settled_p:>3.0f}% ' + f'groups: {len(self.pop.groups):>6,d} ' + f'{Size.bytes2human(self.pop.sim.comp_hist.mem_iter[-1]):>7} ' + f'{Time.tsdiff2human(self.pop.sim.comp_hist.t_iter[-1]):>12}') if self.persistence: self.persistence.persist(self, [ self.pop.m, self.pop.m_out, migrating_m, migrating_p, migrating_time_mean, migrating_time_sd, settled_m, settled_p ], iter, t, traj_id)
def __init__(self, severity, scale, severity_death_mult=0.0001, scale_migration_mult=0.01, name='conflict', t=TimeAlways(), i=IterAlways()): super().__init__(name, t, i, group_qry=GroupQry(cond=[lambda g: g.has_attr({ 'is-migrating': False })])) self.severity = severity # [0=benign .. 1=lethal] self.scale = scale # [0=contained .. 1=wide-spread] self.severity_death_mult = severity_death_mult self.scale_migration_mult = scale_migration_mult
def get_loc_aggr(self): """ Calculate aggregates (currently, sums) of the locations students can be at. """ m_home, p_home = self.pop.get_groups_mass_and_prop( GroupQry(cond=[lambda g: g.is_at_site_name('home')])) m_work, p_work = self.pop.get_groups_mass_and_prop( GroupQry(cond=[lambda g: g.is_at_site_name('work')])) m_school, p_school = self.pop.get_groups_mass_and_prop( GroupQry(cond=[lambda g: g.is_at_site_name('school')])) return { 'm_home': m_home, 'p_home': p_home, 'm_work': m_work, 'p_work': p_work, 'm_school': m_school, 'p_school': p_school }
def apply(self, pop, group, iter, t): p = 0 if group.m >= pop.get_group(GroupQry({'form': "m"})).m / 4: p = 0.1 return [ GroupSplitSpec(p=p, attr_set={"form": "c"}), GroupSplitSpec(p=1 - p) ]
def probes_ls(): school_l = Site(450149323) # 88% low income students school_m = Site(450067740) # 7% low income students return GroupSizeProbe( name=name or str(school.name), queries=[ GroupQry(attr={ 'flu': 's' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'e' }, rel={ 'school': school }), GroupQry(attr={ 'flu': 'r' }, rel={ 'school': school }) ], qry_tot=GroupQry(rel={ 'school': school }), persistance=pp, var_names=['ps', 'pe', 'pr', 'ns', 'ne', 'nr'] ) probes = [ { 'name': 'Low-income school', 'inf': '88% low income students', 'persistenceName': 'low-income', 'id': 450149323 }, { 'name': 'medium-income school', 'inf': '7% low income students', 'persistenceName': 'med-income', 'id': 450067740 } ] return jsonify({ 'res': True, 'probes': probes })
def __init__(self, primary_E_site, sei2r_params, p_home_E, p_social_E, soc_dist_comp_young, soc_dist_comp_old, p_fat_by_age_group): if p_home_E + p_social_E > 1.0: raise ValueError('p_home_E + p_social_E cannot be greater than 1.') self.primary_E_site = primary_E_site # primary exposure site self.sei2r_params = sei2r_params self.p_home_E = p_home_E self.p_social_E = p_social_E self.soc_dist_comp_young = soc_dist_comp_young # social distancing compliance (young people) self.soc_dist_comp_old = soc_dist_comp_old # social distancing compliance (old people) self.p_fat_by_age_group = p_fat_by_age_group super().__init__(f'disease-progress-{self.primary_E_site}', group_qry=GroupQry(cond=[lambda g: g.has_rel(self.primary_E_site)]))
def get_flu_s_sv(pop, group, iter, t): ''' Returns the stochastic vector for the 's' state of the 'flu' attribute. That vector becomes one of the rows of the transition matrix of the underlying discrete-time non-homogenous Markov chain. ''' at = group.get_rel(Site.AT) n = at.get_pop_size() # total population at the group's current location n_i = at.get_pop_size(GroupQry(attr={ 'flu': 'i' })) # infected population at the group's current location p_inf = float(n_i) / float(n) # changes every iteration (i.e., the source of the simulation dynamics) return [1 - p_inf, p_inf, 0.00]
def apply(self, pop, group, iter, t): if group.is_at_site_name('school'): p = group.get_rel('school').get_mass_prop( GroupQry(attr={'flu': 'i'})) else: p = self.p_infection_min if group.get_attr('flu') == 's': return [ GroupSplitSpec(p=1 - p, attr_set={'flu': 's'}), GroupSplitSpec(p=p, attr_set={'flu': 'i'}) ] elif group.get_attr('flu') == 'i': return [ GroupSplitSpec(p=0.95, attr_set={'flu': 'i'}), GroupSplitSpec(p=0.05, attr_set={'flu': 'r'}) ]
def apply(self, pop, group, iter, t): if group.attr['form'] == 'c': mouse_group = pop.get_group(GroupQry({'form': "m"})) p = (mouse_group.m * MICE_REPRODUCTION_RATE) / group.m #mice_group_size/pop_size p = p * TIME_COEFFICIENT return [ GroupSplitSpec(p=p, attr_set={'form': "m"}), GroupSplitSpec(p=1 - p) ] else: return [GroupSplitSpec(p=1)]
def apply(self, pop, group, iter, t): migrating_groups = pop.get_groups( GroupQry(cond=[lambda g: g.has_attr({'is-migrating': True})])) if migrating_groups and len(migrating_groups) > 0: migrating_m = sum([g.m for g in migrating_groups]) migrating_p = migrating_m / pop.m * 100 else: migrating_p = 0 p_death = min( self.env_harshness * self.env_harshness_death_mult + migrating_p * self.migration_death_mult, 1.00) return [ GroupSplitSpec(p=p_death, attr_set=Group.VOID), GroupSplitSpec(p=1 - p_death, attr_set={ 'migration-time': group.get_attr('migration-time') + 1 }) ]
def apply(self, pop, group, iter, t): p = self.p_infection_min if group.is_at_site_name('school'): p = group.get_rel(Site.AT).get_mass_prop(GroupQry(attr={ 'flu': 'i' })) if group.get_attr('flu') == 's': return [ GroupSplitSpec(p=1 - p, attr_set={ 'flu': 's' }), GroupSplitSpec(p=p, attr_set={ 'flu': 'i' }) ] elif group.get_attr('flu') == 'i': return [ GroupSplitSpec(p=0.50, attr_set={ 'flu': 'i' }), GroupSplitSpec(p=0.50, attr_set={ 'flu': 's' }) ] elif group.get_attr('flu') == 'r': return [ GroupSplitSpec(p=0.10, attr_set={ 'flu': 's' }), GroupSplitSpec(p=0.90, attr_set={ 'flu': 'r' }) ] else: raise ValueError("Invalid value for attribute 'flu'")
def apply(self, pop, group, iter, t): # Susceptible: if group.has_attr({'flu': 's'}): p_infection = group.get_mass_at(GroupQry(attr={'flu': 'i'})) return [ GroupSplitSpec(p=p_infection, attr_set={ 'flu': 'i', 'mood': 'annoyed' }), GroupSplitSpec(p=1 - p_infection, attr_set={'flu': 's'}) ] # Infected: if group.has_attr({'flu': 'i'}): return [ GroupSplitSpec(p=0.2, attr_set={ 'flu': 'r', 'mood': 'happy' }), GroupSplitSpec(p=0.5, attr_set={ 'flu': 'i', 'mood': 'bored' }), GroupSplitSpec(p=0.3, attr_set={ 'flu': 'i', 'mood': 'annoyed' }) ] # Recovered: if group.has_attr({'flu': 'r'}): return [ GroupSplitSpec(p=0.9, attr_set={'flu': 'r'}), GroupSplitSpec(p=0.1, attr_set={'flu': 's'}) ]
def apply(self, pop, group, iter, t): if group.m == 0: return [GroupSplitSpec(p=1)] flu_mass = round( self.p * group.get_mass_at(GroupQry(attr={'flu-status': 'i'})) * group.m) move_mass = round(self.move_p * group.m) if group.ga("flu-status") == "i": flu_mass = 0 both_mass = round( ((flu_mass / group.m) * (move_mass / group.m)) * group.m) flu_mass = flu_mass - both_mass move_mass = move_mass - both_mass flu_p = flu_mass / group.m move_p = move_mass / group.m both_p = both_mass / group.m if flu_p + move_p + both_p > 1: flu_p = 0 move_p = 0 both_p = 1 move_ind = random.randint(0, len(self.sites) - 1) return [ GroupSplitSpec(p=move_p, rel_set={Site.AT: self.sites[move_ind]}), GroupSplitSpec(p=flu_p, attr_set={"flu-status": "i"}), GroupSplitSpec(p=both_p, attr_set={"flu-status": "i"}, rel_set={Site.AT: self.sites[move_ind]}), GroupSplitSpec(p=1 - move_p - flu_p - both_p) ]
def apply(self, pop, group, iter, t): # ----- ARGUMENTS ----- a1 = group.get_attr('foo') # a2 = group.get_attr(name='bar') # not legal PRAM code b1 = group.is_at_site('1') b2 = group.is_at_site(site='2') b3 = group.is_at_site_name('3') b4 = group.is_at_site_name(name='4') c1 = group.set_attr('foo', 'bar') c2 = group.set_attr('foo', value='bar') c3 = group.set_attr(name='foo', value='bar') c4 = group.set_attr('foo', 'bar', False) c5 = group.set_attr('foo', 'bar', do_force=False) c6 = group.set_attr('foo', value='bar', do_force=False) c7 = group.set_attr(name='foo', value='bar', do_force=False) d1 = pop.get_group({'one': 1}) d2 = pop.get_group(attr={'one': 1}) d3 = pop.get_group({'one': 1}, {'two': 2}) d4 = pop.get_group({'one': 1}, rel={'two': 2}) d5 = pop.get_group(attr={'one': 1}, rel={'two': 2}) e1 = pop.get_groups_mass(GroupQry({'three': 3})) e2 = pop.get_groups_mass(qry=GroupQry({'three': 3})) e3 = pop.get_groups_mass(GroupQry({'three': 3}), 5) e4 = pop.get_groups_mass(GroupQry({'three': 3}), hist_delta=5) e5 = pop.get_groups_mass(qry=GroupQry({'three': 3}), hist_delta=5) # ----- LAMBDAS ----- f1 = lambda g: g.get_attr('a') > 0 f2 = lambda a, b, c: print(a, b, c) gq1 = GroupQry(cond=[ lambda g1: g1.get_attr('a') > 0, lambda g2: g2.ga('b') < 0, lambda g3: g3.get_mass() == 100, lambda g4: g4.get_rel('origin') == 'a', lambda g5: g5.gr(Site.AT) == 'b', lambda g6: g6.has_attr('foo'), lambda g7: g7.get_site_at().get_groups() ]) return None
def sim03(iter_cnt): sim = (Simulation().add([ ProgressFluIncomeRule(), GroupSizeProbe( 'flu-income', [ GroupQry(attr={ 'income': 'l', 'flu': 's' }), GroupQry(attr={ 'income': 'l', 'flu': 'e' }), GroupQry(attr={ 'income': 'l', 'flu': 'r' }), GroupQry(attr={ 'income': 'm', 'flu': 's' }), GroupQry(attr={ 'income': 'm', 'flu': 'e' }), GroupQry(attr={ 'income': 'm', 'flu': 'r' }) ], msg_mode=ProbeMsgMode.CUMUL, ), Group(m=500, attr={'income': 'l'}), Group(m=500, attr={'income': 'm'}) ]).run(iter_cnt)) print(sim.probes[0].get_msg()) print()