Example #1
0
def cache_populations(seed=0, popfile=None):
    ''' Pre-generate the synthpops population '''

    pars = sc.objdict(
        pop_size=pop_size,
        pop_type='synthpops',
        rand_seed=seed,
    )

    if popfile is None:
        popfile = f'{popfile_stem}{pars.rand_seed}.ppl'

    T = sc.tic()
    print(f'Making "{popfile}"...')
    sim = cv.Sim(pars)
    cv.make_people(sim,
                   popfile=popfile,
                   save_pop=True,
                   with_facilities=True,
                   generate=True,
                   layer_mapping={'LTCF': 'l'})
    sc.toc(T)

    print('Done')
    return
Example #2
0
def test_distances(doplot=False):
    npoints = 1000
    nsamples = 2
    npars = 2
    test = pl.rand(nsamples, npars)
    train = pl.rand(npoints, npars)
    t1 = sc.tic()
    distances = pe.scaled_norm(test=test, train=train)
    t2 = sc.toc(t1, output=True)
    timestr = f'time = {t2*1e3:0.2f} ms'
    print(timestr)
    
    # Test a shape mismatch
    with pytest.raises(ValueError):
        pe.scaled_norm(test=pl.rand(7), train=pl.rand(7,4)) # Should be 4, not 7
        
    if doplot:
        x_ind = 0
        y_ind = 1
        offset = 0.009
        pl.figure(figsize=eqfigsize)
        sc.parulacolormap(apply=True) # or pl.set_map('parula')
        for pt in range(2):
            markers = ['<','>']
            markersize = 50
            bigmarker = 200
            pl.scatter(train[:,x_ind]+offset*pt, train[:,y_ind], s=markersize, c=distances[pt], marker=markers[pt], label=f'Samples {pt+1}')
            pl.scatter(test[pt][0], test[pt][1], s=bigmarker, c='k', marker=markers[pt], label=f'Origin {pt+1}')
        pl.xlabel('Parameter 1')
        pl.ylabel('Parameter 2')
        pl.title(f'Distance calculations (color ∝ distance); {timestr}')
        pl.legend()
        pl.colorbar()
        pl.axis('square')
    return distances
def test_borderclosure(do_plot=False,
                       do_show=True,
                       do_save=False,
                       fig_path=None):
    sc.heading('Test effect of border closures')

    sc.heading('Setting up...')

    sc.tic()

    n_runs = 2
    verbose = 1

    basepars = {'pop_size': 1000}
    basepars = {'n_imports': 5}
    metapars = {'n_runs': n_runs}

    sim = cv.Sim()

    # Define the scenarios
    scenarios = {
        'baseline': {
            'name': 'No border closures',
            'pars': {}
        },
        'borderclosures_day10': {
            'name': 'Close borders on day 10',
            'pars': {
                'interventions':
                [cv.dynamic_pars({'n_imports': {
                    'days': 10,
                    'vals': 0
                }})]
            }
        },
    }

    scens = cv.Scenarios(sim=sim,
                         basepars=basepars,
                         metapars=metapars,
                         scenarios=scenarios)
    scens.run(verbose=verbose, debug=debug)

    if do_plot:
        scens.plot(do_save=do_save, do_show=do_show, fig_path=fig_path)

    return scens
Example #4
0
    def run(self, do_plot=False, verbose=None, **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            verbose (int): level of detail to print
            kwargs (dict): passed to self.plot()

        Returns:
            results: the results object (also modifies in-place)
        '''

        # Initialize
        T = sc.tic()
        if not self.initialized:
            self.initialize()
        if verbose is None:
            verbose = self['verbose']

        # Main simulation loop
        for t in self.tvec:

            # Print progress
            if verbose >= 1:
                elapsed = sc.toc(output=True)
                simlabel = f'"{self.label}": ' if self.label else ''
                string = f'  Running {simlabel}day {t:2.0f}/{self.pars["n_days"]} ({elapsed:0.2f} s) '
                if verbose >= 2:
                    sc.heading(string)
                elif verbose == 1:
                    cvm.progressbar(t + 1,
                                    self.npts,
                                    label=string,
                                    newline=True)

            # Do the heavy lifting -- actually run the model!
            self.step()

            # Check if we were asked to stop
            elapsed = sc.toc(T, output=True)
            if elapsed > self['timelimit']:
                sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1,
                          verbose)
                break
            elif self['stopping_func'] and self['stopping_func'](self):
                sc.printv("Stopping function terminated the simulation", 1,
                          verbose)
                break

        # End of time loop; compute cumulative results outside of the time loop
        self.finalize(verbose=verbose)  # Finalize the results
        sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose)
        self.summary = self.summary_stats(verbose=verbose)
        if do_plot:  # Optionally plot
            self.plot(**kwargs)

        return self.results
Example #5
0
def test_benchmark(do_save=do_save):
    ''' Compare benchmark performance '''

    print('Running benchmark...')
    previous = sc.loadjson(benchmark_filename)

    # Create the sim
    sim = cv.Sim(verbose=0)

    # Time initialization
    t0 = sc.tic()
    sim.initialize()
    t_init = sc.toc(t0, output=True)

    # Time running
    t0 = sc.tic()
    sim.run()
    t_run = sc.toc(t0, output=True)

    # Construct json
    n_decimals = 3
    json = {
        'time': {
            'initialize': round(t_init, n_decimals),
            'run': round(t_run, n_decimals),
        },
        'parameters': {
            'pop_size': sim['pop_size'],
            'pop_type': sim['pop_type'],
            'n_days': sim['n_days'],
        },
    }

    print('Previous benchmark:')
    sc.pp(previous)

    print('\nNew benchmark:')
    sc.pp(json)

    if do_save:
        sc.savejson(filename=benchmark_filename, obj=json, indent=2)

    print('Done.')

    return json
def test_turnaround(do_plot=False, do_show=True, do_save=False, fig_path=None):
    sc.heading('Test impact of reducing delay time for getting test results')

    sc.heading('Setting up...')

    sc.tic()

    n_runs = 3
    verbose = 1
    base_pars = {
      'pop_size': 1000,
      'pop_type': 'hybrid',
      }

    base_sim = cv.Sim(base_pars) # create sim object
    n_people = base_sim['pop_size']
    npts = base_sim.npts

    # Define overall testing assumptions
    testing_prop = 0.1 # Assumes we could test 10% of the population daily (!!)
    daily_tests = [testing_prop*n_people]*npts # Number of daily tests

    # Define the scenarios
    scenarios = {
        f'{d}dayturnaround': {
            'name':f'Symptomatic testing with {d} days to get results',
            'pars': {
                'interventions': cv.test_num(daily_tests=daily_tests, test_delay=d)
            }
        } for d in range(1, 3+1, 2)
    }

    metapars = {'n_runs': n_runs}

    scens = cv.Scenarios(sim=base_sim, metapars=metapars, scenarios=scenarios)
    scens.run(verbose=verbose, debug=debug)

    to_plot = ['cum_infections', 'n_infectious', 'new_tests', 'new_diagnoses']
    fig_args = dict(figsize=(20, 24))

    if do_plot:
        scens.plot(do_save=do_save, do_show=do_show, fig_path=fig_path, interval=7, fig_args=fig_args, to_plot=to_plot)

    return scens
Example #7
0
def make_app(**kwargs):
    T = sc.tic()
    app = sw.ScirisApp(
        name='HealthPrior',
        filepath=__file__,
        config=hp.webapp.config,
        RPC_dict=hp.webapp.rpcs.RPC_dict
    )  # Create the ScirisApp object.  NOTE: app.config will thereafter contain all of the configuration parameters, including for Flask.
    sw.make_default_users(app)
    print('>> Webapp initialization complete (elapsed time: %0.2f s)' %
          sc.toc(T, output=True))
    return app
Example #8
0
def test_parallelization(doplot=False):
    sc.heading('Testing parallelization...')

    print('Running in serial')
    t1i = sc.tic()
    serial_result = pe.shellstep(lambda_func,
                                 startvals,
                                 parallelize=False,
                                 **kwargs)
    t1f = sc.toc(t1i, output=True)

    print('Running in parallel')
    t2i = sc.tic()
    parallel_result = pe.shellstep(wrapped_lambda_func,
                                   startvals,
                                   parallelize=True,
                                   **kwargs)
    t2f = sc.toc(t2i, output=True)

    print(f'Serial time: {t1f:0.3f} s; parallel time: {t2f:0.3f} s')
    return serial_result, parallel_result
Example #9
0
    def run(self, do_plot=False, verbose=None, **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            verbose (int): level of detail to print
            kwargs (dict): passed to self.plot()

        Returns:
            results: the results object (also modifies in-place)
        '''

        T = sc.tic()

        # Reset settings and results
        if not self.initialized:
            self.initialize()

        if verbose is None:
            verbose = self['verbose']

        # Main simulation loop
        for t in range(self.npts):
            self.next(verbose=verbose)

            # Check timing and stopping function
            # Raise an error here because the simulation will be left in an incomplete and potentially
            # unusable state (it would be necessary to continue stepping the simulation and to finalize)
            # Also raising the exception means that we won't progress to finalizing the simulation
            # (which wouldn't make sense if the simulation was terminated anyway)
            # This error could be caught and then the simulation run could be continued simply by
            # calling `sim.run()` again (it will resume where it left off)
            elapsed = sc.toc(T, output=True)
            if elapsed > self['timelimit']:
                raise TimeoutError(
                    f"Time limit ({self['timelimit']} s) exceeded; stopping..."
                )
            elif self['stop_func'] and self['stop_func'](self):
                raise cvu.CancelError(
                    "Stopping function terminated the simulation")

        # End of time loop; compute cumulative results outside of the time loop
        self.finalize(verbose=verbose)  # Finalize the results
        sc.printv(f'\nRun finished after {elapsed:0.1f} s.\n', 1, verbose)
        self.summary = self.summary_stats(verbose=verbose)
        if do_plot:  # Optionally plot
            self.plot(**kwargs)

        return self.results
Example #10
0
File: sim.py Project: willf/covasim
    def run(self, do_plot=False, verbose=None, **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            verbose (int): level of detail to print
            kwargs (dict): passed to self.plot()

        Returns:
            results: the results object (also modifies in-place)
        '''

        T = sc.tic()

        # Reset settings and results
        if not self.initialized:
            self.initialize()

        if verbose is None:
            verbose = self['verbose']

        # Main simulation loop
        for t in range(self.npts):

            # Do the heavy lifting
            self.next(verbose=verbose)

            # Check if we were asked to stop
            elapsed = sc.toc(T, output=True)
            if elapsed > self['timelimit']:
                sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1,
                          verbose)
                break
            elif self['stopping_func'] and self['stopping_func'](self):
                sc.printv("Stopping function terminated the simulation", 1,
                          verbose)
                break

        # End of time loop; compute cumulative results outside of the time loop
        self.finalize(verbose=verbose)  # Finalize the results
        sc.printv(f'\nRun finished after {elapsed:0.1f} s.\n', 1, verbose)
        self.summary = self.summary_stats(verbose=verbose)
        if do_plot:  # Optionally plot
            self.plot(**kwargs)

        return self.results
 def normalize_performance():
     ''' Normalize performance across CPUs -- simple Numpy calculation '''
     t_bls = []
     bl_repeats = 5
     n_outer = 10
     n_inner = 1e6
     for r in range(bl_repeats):
         t0 = sc.tic()
         for i in range(n_outer):
             a = np.random.random(int(n_inner))
             b = np.random.random(int(n_inner))
             a*b
         t_bl = sc.toc(t0, output=True)
         t_bls.append(t_bl)
     t_bl = min(t_bls)
     reference = 0.112 # Benchmarked on an Intel i9-8950HK CPU @ 2.90GHz
     ratio = reference/t_bl
     return ratio
Example #12
0
def cova():

    sc.tic()
    s1 = cv.Sim(pop_size=ps2, pop_type='random')
    s1.initialize()
    sc.toc()

    sc.tic()
    s2 = cv.Sim(pop_size=ps2, pop_type='hybrid')
    s2.initialize()
    sc.toc()

    sc.tic()
    s3 = cv.Sim(pop_size=ps2, pop_type='synthpops')
    s3.initialize()
    sc.toc()

    sc.tic()
    s4 = cv.Sim(pop_size=ps1, pop_type='synthpops')
    s4.initialize()
    sc.toc()

    return [s1, s2, s3, s4]
def cache_populations(seed=0, popfile=None):
    ''' Pre-generate the hybrid population '''

    pars = sc.objdict(
        pop_size=225e3,
        pop_type='hybrid',
        rand_seed=seed,
    )

    if popfile is None:
        popfile = f'inputs/kc_hybrid_seed{pars.rand_seed}.ppl'

    T = sc.tic()
    print(f'Making "{popfile}"...')
    sim = cv.Sim(pars)
    cv.make_people(sim,
                   popfile=popfile,
                   save_pop=True,
                   school_type=True,
                   school_type_ages=[[6, 11], [11, 14], [14, 18], [18, 22]])
    sc.toc(T)

    print('Done')
    return
def test_interventions(do_plot=False,
                       do_show=True,
                       do_save=False,
                       fig_path=None):
    sc.heading('Test of testing interventions')

    sc.heading('Setting up...')

    sc.tic()

    n_runs = 3
    verbose = 1
    base_pars = {
        'pop_size': 1000,
        'pop_type': 'hybrid',
    }

    base_sim = cv.Sim(base_pars)  # create sim object
    n_people = base_sim['pop_size']
    npts = base_sim.npts

    # Define overall testing assumptions
    # Remember that this is the daily % of the population that gets tested. S Korea (one of the highest-testing places) tested
    # an average of 10000 people/day over March, or 270,000 in total. This is ~200 people per million every day (0.02%)....
    max_optimistic_testing = 0.1  # ... which means that this is an artificially high number, for testing purposes only!!
    optimistic_daily_tests = [
        max_optimistic_testing * n_people
    ] * npts  # Very best-case scenario for asymptomatic testing

    # Define the scenarios
    scenarios = {
        'baseline': {
            'name': 'Status quo, no testing',
            'pars': {
                'interventions': None,
            }
        },
        'test_skorea': {
            'name':
            'Assuming South Korea testing levels of 0.02% daily (untargeted); isolate positives',
            'pars': {
                'interventions':
                cv.test_num(daily_tests=optimistic_daily_tests)
            }
        },
        'floating': {
            'name': 'Test with constant probability based on symptoms',
            'pars': {
                'interventions':
                cv.test_prob(symp_prob=max_optimistic_testing, asymp_prob=0.0)
            }
        },
        'sequence': {
            'name': 'Historical switching to probability',
            'pars': {
                'interventions':
                cv.sequence(
                    days=[10, 51],
                    interventions=[
                        cv.test_num(daily_tests=optimistic_daily_tests),
                        cv.test_prob(symp_prob=0.2, asymp_prob=0.002),
                    ])
            }
        },
    }

    metapars = {'n_runs': n_runs}

    scens = cv.Scenarios(sim=base_sim, metapars=metapars, scenarios=scenarios)
    scens.run(verbose=verbose, debug=debug)

    to_plot = ['cum_infections', 'n_infectious', 'new_tests', 'new_diagnoses']
    fig_args = dict(figsize=(20, 24))

    if do_plot:
        scens.plot(do_save=do_save,
                   do_show=do_show,
                   fig_path=fig_path,
                   interval=7,
                   fig_args=fig_args,
                   to_plot=to_plot)

    return scens
def test_tracedelay(do_plot=False, do_show=True, do_save=False, fig_path=None):
    sc.heading(
        'Test impact of reducing delay time for finding contacts of positives')

    sc.heading('Setting up...')

    sc.tic()

    n_runs = 3
    verbose = 1
    base_pars = {
        'pop_size': 1000,
        'pop_type': 'hybrid',
    }

    base_sim = cv.Sim(base_pars)  # create sim object
    base_sim['n_days'] = 50
    base_sim['beta'] = 0.03  # Increase beta

    n_people = base_sim['pop_size']
    npts = base_sim.npts

    # Define overall testing assumptions
    testing_prop = 0.1  # Assumes we could test 10% of the population daily (way too optimistic!!)
    daily_tests = [testing_prop * n_people] * npts  # Number of daily tests

    # Define the scenarios
    scenarios = {
        'lowtrace': {
            'name': 'Poor contact tracing',
            'pars': {
                'quar_eff': {
                    'h': 1,
                    's': 0.5,
                    'w': 0.5,
                    'c': 0.25
                },
                'quar_period':
                7,
                'interventions': [
                    cv.test_num(daily_tests=daily_tests),
                    cv.contact_tracing(trace_probs={
                        'h': 0,
                        's': 0,
                        'w': 0,
                        'c': 0
                    },
                                       trace_time={
                                           'h': 1,
                                           's': 7,
                                           'w': 7,
                                           'c': 7
                                       })
                ]
            }
        },
        'modtrace': {
            'name': 'Moderate contact tracing',
            'pars': {
                'quar_eff': {
                    'h': 0.75,
                    's': 0.25,
                    'w': 0.25,
                    'c': 0.1
                },
                'quar_period':
                10,
                'interventions': [
                    cv.test_num(daily_tests=daily_tests),
                    cv.contact_tracing(trace_probs={
                        'h': 1,
                        's': 0.8,
                        'w': 0.5,
                        'c': 0.1
                    },
                                       trace_time={
                                           'h': 0,
                                           's': 3,
                                           'w': 3,
                                           'c': 8
                                       })
                ]
            }
        },
        'hightrace': {
            'name': 'Fast contact tracing',
            'pars': {
                'quar_eff': {
                    'h': 0.5,
                    's': 0.1,
                    'w': 0.1,
                    'c': 0.1
                },
                'quar_period':
                14,
                'interventions': [
                    cv.test_num(daily_tests=daily_tests),
                    cv.contact_tracing(trace_probs={
                        'h': 1,
                        's': 0.8,
                        'w': 0.8,
                        'c': 0.2
                    },
                                       trace_time={
                                           'h': 0,
                                           's': 1,
                                           'w': 1,
                                           'c': 5
                                       })
                ]
            }
        },
        'alltrace': {
            'name': 'Same-day contact tracing',
            'pars': {
                'quar_eff': {
                    'h': 0.0,
                    's': 0.0,
                    'w': 0.0,
                    'c': 0.0
                },
                'quar_period':
                21,
                'interventions': [
                    cv.test_num(daily_tests=daily_tests),
                    cv.contact_tracing(trace_probs={
                        'h': 1,
                        's': 1,
                        'w': 1,
                        'c': 1
                    },
                                       trace_time={
                                           'h': 0,
                                           's': 1,
                                           'w': 1,
                                           'c': 2
                                       })
                ]
            }
        },
    }

    metapars = {'n_runs': n_runs}

    scens = cv.Scenarios(sim=base_sim, metapars=metapars, scenarios=scenarios)
    scens.run(verbose=verbose, debug=debug)

    if do_plot:
        to_plot = [
            'cum_infections', 'cum_recoveries', 'new_infections',
            'n_quarantined', 'new_quarantined'
        ]
        fig_args = dict(figsize=(24, 16))
        scens.plot(do_save=do_save,
                   do_show=do_show,
                   to_plot=to_plot,
                   fig_path=fig_path,
                   n_cols=2,
                   fig_args=fig_args)

    return scens
def make_population(seed=0, popfile=None):
    ''' Pre-generate the synthpops population '''

    pars = sc.objdict(
        pop_size=10e3,
        pop_type='synthpops',
        rand_seed=seed,
    )

    use_two_group_reduction = True
    average_LTCF_degree = 20
    ltcf_staff_age_min = 20
    ltcf_staff_age_max = 60

    with_school_types = True
    average_class_size = 20
    inter_grade_mixing = 0.1
    average_student_teacher_ratio = 20
    average_teacher_teacher_degree = 3
    teacher_age_min = 25
    teacher_age_max = 75

    with_non_teaching_staff = True
    # if with_non_teaching_staff is False, but generate is True, then average_all_staff_ratio should be average_student_teacher_ratio or 0
    average_student_all_staff_ratio = 11
    average_additional_staff_degree = 20
    staff_age_min = 20
    staff_age_max = 75

    school_mixing_type = {
        'pk': 'clustered',
        'es': 'clustered',
        'ms': 'clustered',
        'hs': 'random',
        'uv': 'random'
    }

    if popfile is None:
        popfile = f'inputs/kc_synthpops_clustered_withstaff_10e3.ppl'

    T = sc.tic()
    print(f'Making "{popfile}"...')
    sim = cv.Sim(pars)
    cv.make_people(
        sim,
        popfile=popfile,
        save_pop=True,
        generate=True,
        with_facilities=True,
        use_two_group_reduction=use_two_group_reduction,
        average_LTCF_degree=average_LTCF_degree,
        ltcf_staff_age_min=ltcf_staff_age_min,
        ltcf_staff_age_max=ltcf_staff_age_max,
        with_school_types=with_school_types,
        school_mixing_type=school_mixing_type,
        average_class_size=average_class_size,
        inter_grade_mixing=inter_grade_mixing,
        average_student_teacher_ratio=average_student_teacher_ratio,
        average_teacher_teacher_degree=average_teacher_teacher_degree,
        teacher_age_min=teacher_age_min,
        teacher_age_max=teacher_age_max,
        with_non_teaching_staff=with_non_teaching_staff,
        average_student_all_staff_ratio=average_student_all_staff_ratio,
        average_additional_staff_degree=average_additional_staff_degree,
        staff_age_min=staff_age_min,
        staff_age_max=staff_age_max)
    sc.toc(T)

    print('Done')
    return
    # 2020-05-10 - 2020-01-27
    days = (sc.readdate("2020-05-10") - sc.readdate("2020-01-27")).days + 1
    yield_num_old = np.zeros(days)
    yield_num_new = np.zeros(days)
    yield_num_flat = np.zeros(days)
    # Need a couple of sims to make sure we are not looking at noise
    stage_old = {'mild': 0, 'sev': 0, 'crit': 0}
    stage_new = {'mild': 0, 'sev': 0, 'crit': 0}
    stage_flat = {'mild': 0, 'sev': 0, 'crit': 0}

    start = 1
    end = 2
    n_run = end - start
    for i in range(start, end):
        sim = single_sim_old(rand_seed=i)
        t = sc.tic()
        sim.run()
        idx = sim.people.diagnosed
        time_num_old = np.append(
            time_num_old,
            sim.people.date_diagnosed[idx] - sim.people.date_symptomatic[idx])
        yield_num_old = yield_num_old + sim.results['test_yield'].values
        idx_dia = sim.people.diagnosed
        idx = ~np.isnan(sim.people.date_symptomatic)
        stage_old['mild'] += sum(idx[idx_dia]) / sum(idx)
        idx = ~np.isnan(sim.people.date_severe)
        stage_old['sev'] += sum(idx[idx_dia]) / sum(idx)
        idx = ~np.isnan(sim.people.date_critical)
        stage_old['crit'] += sum(idx[idx_dia]) / sum(idx)
        sc.toc(t)
Example #18
0
    def run(self, do_plot=False, until=None, verbose=None, **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            until (int): day to run until
            verbose (int): level of detail to print
            kwargs (dict): passed to self.plot()

        Returns:
            results: the results object (also modifies in-place)
        '''

        # Initialize
        T = sc.tic()
        if not self.initialized:
            self.initialize()
        else:
            self.validate_pars(
            )  # We always want to validate the parameters before running
            self.init_interventions()  # And interventions
        if verbose is None:
            verbose = self['verbose']
        if until:
            until = self.day(until)

        # Main simulation loop
        for t in self.tvec:

            # Print progress
            if verbose >= 1:
                elapsed = sc.toc(output=True)
                simlabel = f'"{self.label}": ' if self.label else ''
                string = f'  Running {simlabel}{self.datevec[t]} ({t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) '
                if verbose >= 2:
                    sc.heading(string)
                elif verbose == 1:
                    sc.progressbar(t + 1,
                                   self.npts,
                                   label=string,
                                   length=20,
                                   newline=True)

            # Do the heavy lifting -- actually run the model!
            self.step()

            # Check if we were asked to stop
            elapsed = sc.toc(T, output=True)
            if self['timelimit'] and elapsed > self['timelimit']:
                sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1,
                          verbose)
                break
            elif self['stopping_func'] and self['stopping_func'](self):
                sc.printv("Stopping function terminated the simulation", 1,
                          verbose)
                break
            if self.t == until:  # If until is specified, just stop here
                return

        # End of time loop; compute cumulative results outside of the time loop
        self.finalize(verbose=verbose)  # Finalize the results
        sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose)
        if do_plot:  # Optionally plot
            self.plot(**kwargs)

        return self.results
def make_population(pop_size,
                    rand_seed=1,
                    max_pop_seeds=None,
                    do_save=True,
                    popfile=None,
                    cohorting=True,
                    n_brackets=20,
                    community_contacts=20,
                    **kwargs):
    '''
    Generate the synthpops population.

    Args:
        pop_size (int): number of people in the model
        rand_seed (int): random seed to use for generating the population
        max_pop_seeds (int): if supplied, take the random seed as modulus of this to limit number of populations generated
        do_save (bool): whether to save the population
        popfile (str): if so, where to save it to
        cohorting (bool): whether to use cohorting
        n_brackets (int): whether to use 16- or 20-bracket age bins
        community_contacts (int): how many community contacts there are
        kwargs (dict): passed to sp.make_population()
    '''

    sp.set_nbrackets(
        n_brackets)  # Essential for getting the age distribution right

    pars = sc.objdict(
        n=pop_size,
        rand_seed=rand_seed,
        with_facilities=True,
        use_two_group_reduction=True,
        average_LTCF_degree=20,
        ltcf_staff_age_min=20,
        ltcf_staff_age_max=60,
        with_school_types=True,
        average_class_size=20,
        inter_grade_mixing=0.1,
        average_student_teacher_ratio=20,
        average_teacher_teacher_degree=3,
        teacher_age_min=25,
        teacher_age_max=75,
        with_non_teaching_staff=True,
        # if with_non_teaching_staff is False, but generate is True, then ,average_all_staff_ratio should be average_student_teacher_ratio or 0
        average_student_all_staff_ratio=11,
        average_additional_staff_degree=20,
        staff_age_min=20,
        staff_age_max=75,
    )

    pars.update(kwargs)  # Update any parameters

    # For reference re: school_types
    # school_mixing_type = 'random' means that students in the school have edges randomly chosen from other students, teachers, and non teaching staff across the school. Students, teachers, and non teaching staff are treated the same in terms of edge generation.
    # school_mixing_type = 'age_clustered' means that students in the school have edges mostly within their own age/grade, with teachers, and non teaching staff. Strict classrooms are not generated. Teachers have some additional edges with other teachers.
    # school_mixing_type = 'age_and_class_clustered' means that students are cohorted into classes of students of the same age/grade with at least 1 teacher, and then some have contact with non teaching staff. Teachers have some additional edges with other teachers.

    if cohorting:
        strategy = 'clustered'  # students in pre-k, elementary, and middle school are cohorted into strict classrooms
        pars.school_mixing_type = {
            'pk': 'age_and_class_clustered',
            'es': 'age_and_class_clustered',
            'ms': 'age_and_class_clustered',
            'hs': 'random',
            'uv': 'random'
        }
    else:
        strategy = 'normal'
        pars.school_mixing_type = {
            'pk': 'age_clustered',
            'es': 'age_clustered',
            'ms': 'age_clustered',
            'hs': 'random',
            'uv': 'random'
        }

    if popfile is None:
        popfile = os.path.join(
            'inputs', f'kc_{strategy}_{int(pars.n)}_seed{pars.rand_seed}.ppl')

    T = sc.tic()
    print('Making population...')

    # Make the population
    population = sp.make_population(**pars)

    # Convert to a popdict
    popdict = cv.make_synthpop(population=sc.dcp(population),
                               community_contacts=community_contacts)
    school_ids = [None] * int(pop_size)
    teacher_flag = [False] * int(pop_size)
    staff_flag = [False] * int(pop_size)
    student_flag = [False] * int(pop_size)
    school_types = {'pk': [], 'es': [], 'ms': [], 'hs': [], 'uv': []}
    school_type_by_person = [None] * int(pop_size)
    schools = dict()

    for uid, person in population.items():
        if person['scid'] is not None:
            school_ids[uid] = person['scid']
            school_type_by_person[uid] = person['sc_type']
            if person['scid'] not in school_types[person['sc_type']]:
                school_types[person['sc_type']].append(person['scid'])
            if person['scid'] in schools:
                schools[person['scid']].append(uid)
            else:
                schools[person['scid']] = [uid]
            if person['sc_teacher'] is not None:
                teacher_flag[uid] = True
            elif person['sc_student'] is not None:
                student_flag[uid] = True
            elif person['sc_staff'] is not None:
                staff_flag[uid] = True

    popdict['school_id'] = np.array(school_ids)
    popdict['schools'] = schools
    popdict['teacher_flag'] = teacher_flag
    popdict['student_flag'] = student_flag
    popdict['staff_flag'] = staff_flag
    popdict['school_types'] = school_types
    popdict['school_type_by_person'] = school_type_by_person

    assert sum(
        popdict['teacher_flag']
    ), 'Uh-oh, no teachers were found: as a school analysis this is treated as an error'
    assert sum(
        popdict['student_flag']
    ), 'Uh-oh, no students were found: as a school analysis this is treated as an error'

    # Actually create the people
    people_pars = dict(
        pop_size=pars.n,
        beta_layer={k: 1.0
                    for k in 'hswcl'
                    },  # Since this is used to define hat layers exist
        beta=
        1.0,  # TODO: this is required for plotting (people.plot()), but shouldn't be
    )
    people = cv.People(people_pars,
                       strict=False,
                       uid=popdict['uid'],
                       age=popdict['age'],
                       sex=popdict['sex'],
                       contacts=popdict['contacts'],
                       school_id=popdict['school_id'],
                       schools=popdict['schools'],
                       school_types=popdict['school_types'],
                       student_flag=popdict['student_flag'],
                       teacher_flag=popdict['teacher_flag'],
                       staff_flag=popdict['staff_flag'],
                       school_type_by_person=popdict['school_type_by_person'])

    if do_save:
        print(f'Saving to "{popfile}"...')
        sc.saveobj(popfile, people)

    sc.toc(T)

    print('Done')
    return people
Example #20
0
    def run(self, initialize=True, do_plot=False, verbose=None, **kwargs):
        ''' Run the simulation '''

        T = sc.tic()

        # Reset settings and results
        if verbose is None:
            verbose = self['verbose']
        if initialize:
            self.initialize()  # Create people, results, etc.

        # Main simulation loop
        self.stopped = False  # We've just been asked to run, so ensure we're unstopped
        for t in range(self.npts):

            # Check timing and stopping function
            elapsed = sc.toc(T, output=True)
            if elapsed > self['timelimit']:
                print(
                    f"Time limit ({self['timelimit']} s) exceeded; stopping..."
                )
                self.stopped = {
                    'why': 'timelimit',
                    'message': 'Time limit exceeded at step {t}',
                    't': t
                }

            if self['stop_func']:
                self.stopped = self['stop_func'](
                    self,
                    t)  # Feed in the current simulation object and the time

            # If this gets set, stop running -- e.g. if the time limit is exceeded
            if self.stopped:
                break

            # Zero counts for this time step.
            n_susceptible = 0
            n_exposed = 0
            n_deaths = 0
            n_recoveries = 0
            n_infectious = 0
            n_infections = 0
            n_symptomatic = 0
            n_recovered = 0

            # Extract these for later use. The values do not change in the person loop and the dictionary lookup is expensive.
            rand_popdata = (self['usepopdata'] == 'random')
            beta = self['beta']
            asym_factor = self['asym_factor']
            diag_factor = self['diag_factor']
            cont_factor = self['cont_factor']
            beta_pop = self['beta_pop']

            # Print progress
            if verbose >= 1:
                string = f'  Running day {t:0.0f} of {self.pars["n_days"]} ({elapsed:0.2f} s elapsed)...'
                if verbose >= 2:
                    sc.heading(string)
                else:
                    print(string)

            # Update each person, skipping people who are susceptible
            not_susceptible = filter(lambda p: not p.susceptible,
                                     self.people.values())
            n_susceptible = len(self.people)

            for person in not_susceptible:
                n_susceptible -= 1

                # If exposed, check if the person becomes infectious or develops symptoms
                if person.exposed:
                    n_exposed += 1
                    if not person.infectious and t >= person.date_infectious:  # It's the day they become infectious
                        person.infectious = True
                        sc.printv(
                            f'      Person {person.uid} became infectious!', 2,
                            verbose)
                    if not person.symptomatic and person.date_symptomatic is not None and t >= person.date_symptomatic:  # It's the day they develop symptoms
                        person.symptomatic = True
                        sc.printv(
                            f'      Person {person.uid} developed symptoms!',
                            2, verbose)

                # If infectious, check if anyone gets infected
                if person.infectious:

                    # Check for death
                    died = person.check_death(t)
                    n_deaths += died

                    # Check for recovery
                    recovered = person.check_recovery(t)
                    n_recoveries += recovered

                    # If the person didn't die or recover, check for onward transmission
                    if not died and not recovered:
                        n_infectious += 1  # Count this person as infectious

                        # Calculate transmission risk based on whether they're asymptomatic/diagnosed/have been isolated
                        thisbeta = beta * \
                                   (asym_factor if person.symptomatic else 1.) * \
                                   (diag_factor if person.diagnosed else 1.) * \
                                   (cont_factor if person.known_contact else 1.)

                        # Determine who gets infected
                        if rand_popdata:  # Flat contacts
                            transmission_inds = cvu.bf(thisbeta,
                                                       person.contacts)
                        else:  # Dictionary of contacts -- extra loop over layers
                            transmission_inds = []
                            for ckey in self.contact_keys:
                                layer_beta = thisbeta * beta_pop[ckey]
                                transmission_inds.extend(
                                    cvu.bf(layer_beta, person.contacts[ckey]))

                        # Loop over people who do
                        for contact_ind in transmission_inds:
                            target_person = self.get_person(
                                contact_ind)  # Stored by integer

                            # This person was diagnosed last time step: time to flag their contacts
                            if person.date_diagnosed is not None and person.date_diagnosed == t - 1:
                                target_person.known_contact = True

                            # Skip people who are not susceptible
                            if target_person.susceptible:
                                n_infections += target_person.infect(
                                    t, person)  # Actually infect them
                                sc.printv(
                                    f'        Person {person.uid} infected person {target_person.uid}!',
                                    2, verbose)

                # Count people who developed symptoms
                if person.symptomatic:
                    n_symptomatic += 1

                # Count people who recovered
                if person.recovered:
                    n_recovered += 1

            # End of person loop; apply interventions
            for intervention in self['interventions']:
                intervention.apply(self, t)
            if self['interv_func'] is not None:  # Apply custom intervention function
                self = self['interv_func'](self, t)

            # Update counts for this time step
            self.results['n_susceptible'][t] = n_susceptible
            self.results['n_exposed'][t] = n_exposed
            self.results['deaths'][t] = n_deaths
            self.results['recoveries'][t] = n_recoveries
            self.results['n_infectious'][t] = n_infectious
            self.results['infections'][t] = n_infections
            self.results['n_symptomatic'][t] = n_symptomatic
            self.results['n_recovered'][t] = n_recovered

        # End of time loop; compute cumulative results outside of the time loop
        self.results['cum_exposed'].values = pl.cumsum(
            self.results['infections'].values) + self[
                'n_infected']  # Include initially infected people
        self.results['cum_tested'].values = pl.cumsum(
            self.results['tests'].values)
        self.results['cum_diagnosed'].values = pl.cumsum(
            self.results['diagnoses'].values)
        self.results['cum_deaths'].values = pl.cumsum(
            self.results['deaths'].values)
        self.results['cum_recoveries'].values = pl.cumsum(
            self.results['recoveries'].values)

        # Add in the results from the interventions
        for intervention in self['interventions']:
            intervention.finalize(self)  # Execute any post-processing

        # Scale the results
        for reskey in self.reskeys:
            if self.results[reskey].scale:
                self.results[reskey].values *= self['scale']

        # Perform calculations on results
        self.compute_doubling()
        self.compute_r_eff()
        self.likelihood()

        # Tidy up
        self.results_ready = True
        sc.printv(f'\nRun finished after {elapsed:0.1f} s.\n', 1, verbose)
        self.results['summary'] = self.summary_stats()

        if do_plot:
            self.plot(**kwargs)

        # Convert to an odict to allow e.g. sim.people[25] later, and results to an objdict to allow e.g. sim.results.diagnoses
        self.people = sc.odict(self.people)
        self.results = sc.objdict(self.results)

        return self.results
Example #21
0
    def run(self,
            do_plot=False,
            until=None,
            restore_pars=True,
            reset_seed=True,
            verbose=None,
            **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            until (int): day to run until
            restore_pars (bool): whether to make a copy of the parameters before the run and restore it after, so runs are repeatable
            reset_seed (bool): whether to reset the random number stream immediately before run
            verbose (float): level of detail to print, e.g. 0 = no output, 0.2 = print every 5th day, 1 = print every day
            kwargs (dict): passed to sim.plot()

        Returns:
            results (dict): the results object (also modifies in-place)
        '''

        # Initialize
        T = sc.tic()
        if not self.initialized:
            self.initialize()
        else:
            self.validate_pars(
            )  # We always want to validate the parameters before running
            self.init_interventions()  # And interventions
            if reset_seed:
                self.set_seed(
                )  # Ensure the random number generator is freshly initialized
        if restore_pars:
            orig_pars = sc.dcp(
                self.pars
            )  # Create a copy of the parameters, to restore after the run, in case they are dynamically modified
        if verbose is None:
            verbose = self['verbose']
        if until:
            until = self.day(until)

        # Main simulation loop
        for t in self.tvec:

            # Print progress
            if verbose:
                elapsed = sc.toc(output=True)
                simlabel = f'"{self.label}": ' if self.label else ''
                string = f'  Running {simlabel}{self.datevec[t]} ({t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) '
                if verbose >= 2:
                    sc.heading(string)
                else:
                    if not (t % int(1.0 / verbose)):
                        sc.progressbar(t + 1,
                                       self.npts,
                                       label=string,
                                       length=20,
                                       newline=True)

            # Do the heavy lifting -- actually run the model!
            self.step()

            # Check if we were asked to stop
            elapsed = sc.toc(T, output=True)
            if self['timelimit'] and elapsed > self['timelimit']:
                sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1,
                          verbose)
                break
            elif self['stopping_func'] and self['stopping_func'](self):
                sc.printv("Stopping function terminated the simulation", 1,
                          verbose)
                break
            if self.t == until:  # If until is specified, just stop here
                return

        # End of time loop; compute cumulative results outside of the time loop
        self.finalize(verbose=verbose)  # Finalize the results
        sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose)
        if restore_pars:
            self.restore_pars(orig_pars)
        if do_plot:  # Optionally plot
            self.plot(**kwargs)

        return self.results
Example #22
0
    def _do_RPC(self, verbose=False):
        # Check to see whether the RPC is getting passed in in request.form.
        # If so, we are doing an upload, and we want to download the RPC
        # request info from the form, not request.data.
        if 'funcname' in request.form:  # Pull out the function name, args, and kwargs
            fn_name = request.form.get('funcname')
            try:
                args = json.loads(request.form.get('args', "[]"),
                                  object_pairs_hook=OrderedDict)
            except:
                args = []  # May or may not be present
            try:
                kwargs = json.loads(request.form.get('kwargs', "{}"),
                                    object_pairs_hook=OrderedDict)
            except:
                kwargs = {}  # May or may not be present
        else:  # Otherwise, we have a normal or download RPC, which means we pull the RPC request info from request.data.
            reqdict = json.loads(request.data, object_pairs_hook=OrderedDict)
            fn_name = reqdict['funcname']
            args = reqdict.get('args', [])
            kwargs = reqdict.get('kwargs', {})
        if verbose:
            print('RPC(): RPC properties:')
            print('  fn_name: %s' % fn_name)
            print('     args: %s' % args)
            print('   kwargs: %s' % kwargs)

        # If the function name is not in the RPC dictionary, return an error.
        if not sc.isstring(fn_name):
            return robustjsonify(
                {'error': 'Invalid RPC - must be a string (%s)' % fn_name})

        if not fn_name in self.RPC_dict:
            return robustjsonify(
                {'error': 'Could not find requested RPC "%s"' % fn_name})

        found_RPC = self.RPC_dict[fn_name]  # Get the RPC we've found.

        ## Do any validation checks we need to do and return errors if they don't pass.

        # If the RPC is disabled, always return a Status 403 (Forbidden)
        if found_RPC.validation == 'disabled':
            if verbose: print('RPC(): RPC disabled')
            abort(403)

        # Only do other validation if DataStore and users are included -- NOTE: Any "unknown" validation values are treated like 'none'.
        if self.config['USE_DATASTORE'] and self.config['USE_USERS']:
            if found_RPC.validation == 'any' and not (
                    current_user.is_anonymous
                    or current_user.is_authenticated):
                abort(
                    401
                )  # If the RPC should be executable by any user, including an anonymous one, but there is no authorization or anonymous login, return a Status 401 (Unauthorized)
            elif found_RPC.validation == 'named' and (
                    current_user.is_anonymous
                    or not current_user.is_authenticated):
                abort(
                    401
                )  # Else if the RPC should be executable by any non-anonymous user, but there is no authorization or there is an anonymous login, return a Status 401 (Unauthorized)
            elif found_RPC.validation == 'admin':  # Else if the RPC should be executable by any admin user, but there is no admin login or it's an anonymous login...
                if current_user.is_anonymous or not current_user.is_authenticated:
                    abort(
                        401
                    )  # If the user is anonymous or no authenticated user is logged in, return Status 401 (Unauthorized).
                elif not current_user.is_admin:
                    abort(
                        403
                    )  # Else, if the user is not an admin user, return Status 403 (Forbidden).

        # If we are doing an upload...
        if found_RPC.call_type == 'upload':
            if verbose: print('Starting upload...')
            thisfile = request.files[
                'uploadfile']  # Grab the formData file that was uploaded.
            filename = secure_filename(
                thisfile.filename
            )  # Extract a sanitized filename from the one we start with.
            try:
                uploaded_fname = os.path.join(
                    self.datastore.tempfolder,
                    filename)  # Generate a full upload path/file name.
            except Exception as E:
                errormsg = 'Could not create filename for uploaded file: %s' % str(
                    E)
                raise Exception(errormsg)
            try:
                thisfile.save(
                    uploaded_fname)  # Save the file to the uploads directory
            except Exception as E:
                errormsg = 'Could not save uploaded file: %s' % str(E)
                raise Exception(errormsg)
            args.insert(
                0, uploaded_fname)  # Prepend the file name to the args list.

        # Show the call of the function.
        callcolor = ['cyan', 'bgblue']
        successcolor = ['green', 'bgblue']
        failcolor = ['gray', 'bgred']
        timestr = '[%s]' % sc.now(astype='str')
        try:
            userstr = ' <%s>' % current_user.username
        except:
            userstr = ' <no user>'
        RPCinfo = sc.objdict({
            'time': timestr,
            'user': userstr,
            'module': found_RPC.call_func.__module__,
            'name': found_RPC.funcname
        })

        if self.config['LOGGING_MODE'] == 'FULL':
            string = '%s%s RPC called: "%s.%s"' % (
                RPCinfo.time, RPCinfo.user, RPCinfo.module, RPCinfo.name)
            sc.colorize(callcolor, string, enable=self.colorize)

        # Execute the function to get the results, putting it in a try block in case there are errors in what's being called.
        try:
            if verbose: print('RPC(): Starting RPC...')
            T = sc.tic()
            result = found_RPC.call_func(*args, **kwargs)
            if isinstance(
                    result, dict
            ) and 'error' in result:  # If the RPC returns an error, return it
                return robustjsonify({'error': result['error']})
            elapsed = sc.toc(T, output=True)
            if self.config['LOGGING_MODE'] == 'FULL':
                string = '%s%s RPC finished in %0.2f s: "%s.%s"' % (
                    RPCinfo.time, RPCinfo.user, elapsed, RPCinfo.module,
                    RPCinfo.name)
                sc.colorize(successcolor, string, enable=self.colorize)
        except Exception as E:
            if verbose: print('RPC(): Exception encountered...')
            shortmsg = str(E)
            exception = traceback.format_exc()  # Grab the trackback stack
            hostname = '|%s| ' % socket.gethostname()
            tracemsg = '%s%s%s Exception during RPC "%s.%s" \nRequest: %s \n%.10000s' % (
                hostname, RPCinfo.time, RPCinfo.user, RPCinfo.module,
                RPCinfo.name, request, exception)
            sc.colorize(
                failcolor, tracemsg, enable=self.colorize
            )  # Post an error to the Flask logger limiting the exception information to 10000 characters maximum (to prevent monstrous sqlalchemy outputs)
            if self.config['SLACK']:
                self.slacknotification(tracemsg)
            if isinstance(
                    E, HTTPException
            ):  # If we have a werkzeug exception, pass it on up to werkzeug to resolve and reply to.
                raise E
            code = 500  # Send back a response with status 500 that includes the exception traceback.
            fullmsg = shortmsg + '\n\nException details:\n' + tracemsg
            reply = {
                'exception': fullmsg
            }  # NB, not sure how to actually access 'traceback' on the FE, but keeping it here for future
            return make_response(robustjsonify(reply), code)

        # If we are doing a download, prepare the response and send it off.
        if found_RPC.call_type == 'download':
            # To download a file, use `this.$sciris.download` instead of `this.$sciris.rpc`. Decorate the RPC with
            # `@RPC(call_type='download')`. Finally, the RPC needs to specify the file and optionally the filename.
            # This is done with tuple unpacking. The following outputs are supported from `rpc_function()`
            #
            # 1 - filename_on_disk
            # 2 - BytesIO
            # 3 - filename_on_disk, download_filename
            # 4- BytesIO, download_filename
            #
            # Examples return values from the RPC are as follows
            #
            # 1 - "E:/test.xlsx" (uses "test.xlsx")
            # 2 - <BytesIO> (default filename will be generated in this function)
            # 3 - ("E:/test.xlsx","foo.xlsx")
            # 4 - (<BytesIO>,"foo.xlsx")
            #
            # On the RPC end, the most common cases would be it might look like
            #
            # return "E:/test.xlsx"
            #
            # OR
            #
            # return Blobject.to_file(), "foo.xlsx"

            if verbose: print('RPC(): Starting download...')

            if result is None:  # If we got None for a result (the full file name), return an error to the client.
                return robustjsonify({
                    'error':
                    'Could not find resource to download from RPC "%s": result is None'
                    % fn_name
                })
            elif sc.isstring(result):
                from_file = True
                dir_name, file_name = os.path.split(result)
                output_name = file_name
            elif isinstance(result, io.BytesIO):
                from_file = False
                bytesio = result
                output_name = 'download.obj'
            else:
                try:
                    content = result[0]
                    output_name = result[1]
                    if sc.isstring(content):
                        from_file = True
                        dir_name, file_name = os.path.split(content)
                    elif isinstance(content, io.BytesIO):
                        from_file = False
                        bytesio = content
                    else:
                        return robustjsonify(
                            {'error': 'Unrecognized RPC output'})
                except Exception as E:
                    return robustjsonify(
                        {'error': 'Error reading RPC result (%s)' % E})

            if from_file:
                response = send_from_directory(dir_name,
                                               file_name,
                                               as_attachment=True)
                response.status_code = 201  # Status 201 = Created
                # Unfortunately, we cannot remove the actual file at this point
                # because it is in use during the actual download, so we rely on
                # later cleanup to remove download files.
            else:
                response = send_file(bytesio,
                                     as_attachment=True,
                                     attachment_filename=output_name)
            response.headers['filename'] = output_name
            print(response)
            return response  # Return the response message.

        # Otherwise (normal and upload RPCs),
        else:
            if found_RPC.call_type == 'upload':  # If we are doing an upload....
                try:
                    os.remove(
                        uploaded_fname
                    )  # Erase the physical uploaded file, since it is no longer needed.
                    if verbose:
                        print('RPC(): Removed uploaded file: %s' %
                              uploaded_fname)
                except Exception as E:
                    if verbose:
                        print('RPC(): Could not remove uploaded file: %s' %
                              str(E))  # Probably since moved by the user
            if result is None:  # If None was returned by the RPC function, return ''.
                if verbose: print('RPC(): RPC finished, returning None')
                return ''
            else:  # Otherwise, convert the result (probably a dict) to JSON and return it.
                output = robustjsonify(result)
                if verbose: print('RPC(): RPC finished, returning result')
                return output
Example #23
0
def make_study(restart=True):
    ''' Make a study, deleting one if it already exists '''
    try:
        if restart:
            print(f'About to delete {storage}:{name}, you have 5 seconds to intervene!')
            sc.timedsleep(5.0)
            op.delete_study(storage=storage, study_name=name)
    except:
        pass

    output = op.create_study(storage=storage, study_name=name, load_if_exists=not(restart))
    return output


if __name__ == '__main__':
    t0 = sc.tic()
    make_study(restart=False)
    run_workers()
    study = op.load_study(storage=storage, study_name=name)
    best_pars = study.best_params
    T = sc.toc(t0, output=True)
    print(f'Output: {best_pars}, time: {T}')

    sc.heading('Loading data...')
    best = cs.define_pars('best')
    bounds = cs.define_pars('bounds')

    sc.heading('Making results structure...')
    results = []

    failed_trials = []
Example #24
0
if __name__ == '__main__':

    datadir = sp.datadir

    state_location = 'Washington'
    location = 'seattle_metro'
    country_location = 'usa'

    popdict = {}

    n = 20000

    options_args = {'use_microstructure': True}
    network_distr_args = {'Npop': int(n)}

    sc.tic()
    contacts = sp.make_contacts(popdict,
                                state_location=state_location,
                                location=location,
                                options_args=options_args,
                                network_distr_args=network_distr_args)
    # uids = contacts.keys()
    # uids = [uid for uid in uids]
    # print(contacts[uids[3]]['contacts'])

    # contacts = sp.trim_contacts(contacts,trimmed_size_dic=None,use_clusters=False)
    # print(contacts[uids[3]]['contacts'])

    sp.save_synthpop(
        os.path.join(datadir, 'demographics', country_location,
                     state_location), contacts)
def test_benchmark(do_save=do_save):
    ''' Compare benchmark performance '''

    print('Running benchmark...')
    previous = sc.loadjson(benchmark_filename)

    repeats = 5
    t_inits = []
    t_runs  = []

    def normalize_performance():
        ''' Normalize performance across CPUs -- simple Numpy calculation '''
        t_bls = []
        bl_repeats = 5
        n_outer = 10
        n_inner = 1e6
        for r in range(bl_repeats):
            t0 = sc.tic()
            for i in range(n_outer):
                a = np.random.random(int(n_inner))
                b = np.random.random(int(n_inner))
                a*b
            t_bl = sc.toc(t0, output=True)
            t_bls.append(t_bl)
        t_bl = min(t_bls)
        reference = 0.112 # Benchmarked on an Intel i9-8950HK CPU @ 2.90GHz
        ratio = reference/t_bl
        return ratio


    # Test CPU performance before the run
    r1 = normalize_performance()

    # Do the actual benchmarking
    for r in range(repeats):

        # Create the sim
        sim = cv.Sim(verbose=0)

        # Time initialization
        t0 = sc.tic()
        sim.initialize()
        t_init = sc.toc(t0, output=True)

        # Time running
        t0 = sc.tic()
        sim.run()
        t_run = sc.toc(t0, output=True)

        # Store results
        t_inits.append(t_init)
        t_runs.append(t_run)

    # Test CPU performance after the run
    r2 = normalize_performance()
    ratio = (r1+r2)/2
    t_init = min(t_inits)*ratio
    t_run  = min(t_runs)*ratio

    # Construct json
    n_decimals = 3
    json = {'time': {
                'initialize': round(t_init, n_decimals),
                'run':        round(t_run,  n_decimals),
                },
            'parameters': {
                'pop_size': sim['pop_size'],
                'pop_type': sim['pop_type'],
                'n_days':   sim['n_days'],
                },
            'cpu_performance': ratio,
            }

    print('Previous benchmark:')
    sc.pp(previous)

    print('\nNew benchmark:')
    sc.pp(json)

    if do_save:
        sc.savejson(filename=benchmark_filename, obj=json, indent=2)

    print('Done.')

    return json
Example #26
0
    def run(self, do_plot=False, until=None, restore_pars=True, reset_seed=True, verbose=None, **kwargs):
        '''
        Run the simulation.

        Args:
            do_plot (bool): whether to plot
            until (int/str): day or date to run until
            restore_pars (bool): whether to make a copy of the parameters before the run and restore it after, so runs are repeatable
            reset_seed (bool): whether to reset the random number stream immediately before run
            verbose (float): level of detail to print, e.g. 0 = no output, 0.2 = print every 5th day, 1 = print every day
            kwargs (dict): passed to sim.plot()

        Returns:
            results (dict): the results object (also modifies in-place)
        '''

        # Initialization steps -- start the timer, initialize the sim and the seed, and check that the sim hasn't been run
        T = sc.tic()

        if verbose is None:
            verbose = self['verbose']

        if not self.initialized:
            self.initialize()
            self._orig_pars = sc.dcp(self.pars) # Create a copy of the parameters, to restore after the run, in case they are dynamically modified

        if reset_seed:
            # Reset the RNG. If the simulation is newly created, then the RNG will be reset by sim.initialize() so the use case
            # for resetting the seed here is if the simulation has been partially run, and changing the seed is required
            self.set_seed()

        until = self.npts if until is None else self.day(until)
        if until > self.npts:
            raise AlreadyRunError(f'Requested to run until t={until} but the simulation end is t={self.npts}')

        if self.complete:
            raise AlreadyRunError('Simulation is already complete (call sim.initialize() to re-run)')

        if self.t >= until: # NB. At the start, self.t is None so this check must occur after initialization
            raise AlreadyRunError(f'Simulation is currently at t={self.t}, requested to run until t={until} which has already been reached')

        # Main simulation loop
        while self.t < until:

            # Check if we were asked to stop
            elapsed = sc.toc(T, output=True)
            if self['timelimit'] and elapsed > self['timelimit']:
                sc.printv(f"Time limit ({self['timelimit']} s) exceeded; call sim.finalize() to compute results if desired", 1, verbose)
                return
            elif self['stopping_func'] and self['stopping_func'](self):
                sc.printv("Stopping function terminated the simulation; call sim.finalize() to compute results if desired", 1, verbose)
                return

            # Print progress
            if verbose:
                simlabel = f'"{self.label}": ' if self.label else ''
                string = f'  Running {simlabel}{self.datevec[self.t]} ({self.t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) '
                if verbose >= 2:
                    sc.heading(string)
                else:
                    if not (self.t % int(1.0/verbose)):
                        sc.progressbar(self.t+1, self.npts, label=string, length=20, newline=True)

            # Do the heavy lifting -- actually run the model!
            self.step()

        # If simulation reached the end, finalize the results
        if self.complete:
            self.finalize(verbose=verbose, restore_pars=restore_pars)
            sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose)
            if do_plot: # Optionally plot
                self.plot(**kwargs)
            return self.results
        else:
            return # If not complete, return nothing
def test_generate_microstructures_with_non_teaching_staff():
    # # generate and write to file
    population1 = sp.generate_microstructure_with_facilities(
        datadir,
        location=location,
        state_location=state_location,
        country_location=country_location,
        n=n,
        use_two_group_reduction=use_two_group_reduction,
        average_LTCF_degree=average_LTCF_degree,
        ltcf_staff_age_min=ltcf_staff_age_min,
        ltcf_staff_age_max=ltcf_staff_age_max,
        with_school_types=with_school_types,
        school_mixing_type=school_mixing_type,
        average_class_size=average_class_size,
        inter_grade_mixing=inter_grade_mixing,
        average_student_teacher_ratio=average_student_teacher_ratio,
        average_teacher_teacher_degree=average_teacher_teacher_degree,
        teacher_age_min=teacher_age_min,
        teacher_age_max=teacher_age_max,
        average_student_all_staff_ratio=average_student_all_staff_ratio,
        average_additional_staff_degree=average_additional_staff_degree,
        staff_age_min=staff_age_min,
        staff_age_max=staff_age_max,
        write=write,
        plot=plot,
        return_popdict=return_popdict,
        use_default=use_default)

    # # # read in from file
    population2 = sp.make_contacts_with_facilities_from_microstructure(
        datadir,
        location=location,
        state_location=state_location,
        country_location=country_location,
        n=n,
        use_two_group_reduction=use_two_group_reduction,
        average_LTCF_degree=average_LTCF_degree,
        with_school_types=with_school_types,
        school_mixing_type=school_mixing_type,
        average_class_size=average_class_size,
        inter_grade_mixing=inter_grade_mixing,
        average_student_teacher_ratio=average_student_teacher_ratio,
        average_teacher_teacher_degree=average_teacher_teacher_degree,
        average_student_all_staff_ratio=average_student_all_staff_ratio,
        average_additional_staff_degree=average_additional_staff_degree)

    # # generate on the fly
    sc.tic()
    population3 = sp.make_population(
        n=n,
        generate=True,
        with_facilities=True,
        use_two_group_reduction=use_two_group_reduction,
        average_LTCF_degree=average_LTCF_degree,
        ltcf_staff_age_min=ltcf_staff_age_min,
        ltcf_staff_age_max=ltcf_staff_age_max,
        with_school_types=with_school_types,
        school_mixing_type=school_mixing_type,
        average_class_size=average_class_size,
        inter_grade_mixing=inter_grade_mixing,
        average_student_teacher_ratio=average_student_teacher_ratio,
        average_teacher_teacher_degree=average_teacher_teacher_degree,
        teacher_age_min=teacher_age_min,
        teacher_age_max=teacher_age_max,
        with_non_teaching_staff=with_non_teaching_staff,
        average_student_all_staff_ratio=average_student_all_staff_ratio,
        average_additional_staff_degree=average_additional_staff_degree,
        staff_age_min=staff_age_min,
        staff_age_max=staff_age_max,
        rand_seed=rand_seed)
    sc.toc()

    sp.check_all_residents_are_connected_to_staff(population3)

    return population1, population2, population3
Example #28
0
def test_beds(do_plot=False, do_show=True, do_save=False, fig_path=None):
    sc.heading('Test of bed capacity estimation')

    sc.heading('Setting up...')

    sc.tic()

    n_runs = 3
    verbose = 1

    basepars = {'pop_size': 1000}
    metapars = {'n_runs': n_runs}

    sim = cv.Sim()

    # Define the scenarios
    scenarios = {
        'baseline': {
            'name': 'No bed constraints',
            'pars': {
                'pop_infected': 100
            }
        },
        'bedconstraint': {
            'name': 'Only 10 beds available',
            'pars': {
                'pop_infected': 100,
                'n_beds': 10,
            }
        },
        'bedconstraint2': {
            'name': 'Only 1 bed available',
            'pars': {
                'pop_infected': 100,
                'n_beds': 1,
                # 'OR_no_treat': 10., # nb. scenarios cannot currently overwrite nested parameters
                # This prevents overwriting OR_no_treat due to recent refactoring but more generally
                # there are other nested parameters eg. all of those under pars['dur']
            }
        },
    }

    scens = cv.Scenarios(sim=sim,
                         basepars=basepars,
                         metapars=metapars,
                         scenarios=scenarios)
    scens.run(verbose=verbose, debug=debug)

    if do_plot:
        to_plot = sc.odict({
            'cum_deaths': 'Cumulative deaths',
            'bed_capacity': 'People needing beds / beds',
            'n_severe': 'Number of cases requiring hospitalization',
            'n_critical': 'Number of cases requiring ICU',
        })
        scens.plot(to_plot=to_plot,
                   do_save=do_save,
                   do_show=do_show,
                   fig_path=fig_path)

    return scens
Example #29
0
'''
Test plotting functions
'''

import pylab as pl
import sciris as sc
import synthpops as sp
import settings


def test_plots(do_plot=False):
    ''' Basic plots '''
    if not do_plot:
        pl.switch_backend('agg')  # Plot but don't show
    pop = sp.Pop(
        n=settings.pop_sizes.small_medium)  # default parameters, 5k people
    fig1 = pop.plot_people()  # equivalent to cv.Sim.people.plot()
    fig2 = pop.plot_contacts()  # equivalent to sp.plot_contact_matrix(popdict)
    return [fig1, fig2]


if __name__ == '__main__':

    T = sc.tic()

    figs = test_plots(do_plot=True)

    sc.toc(T)
    print('Done.')
Example #30
0
    def run(self,
            seed_infections=1,
            verbose=None,
            calc_likelihood=False,
            do_plot=False,
            **kwargs):
        ''' Run the simulation '''

        T = sc.tic()

        # Reset settings and results
        if verbose is None:
            verbose = self['verbose']
        self.init_results()
        self.init_people(
            seed_infections=seed_infections)  # Actually create the people
        daily_tests = self.data[
            'new_tests']  # Number of tests each day, from the data
        evacuated = self.data['evacuated']  # Number of people evacuated

        # Main simulation loop
        for t in range(self.npts):

            # Print progress
            if verbose >= 1:
                string = f'  Running day {t:0.0f} of {self["n_days"]}...'
                if verbose >= 2:
                    sc.heading(string)
                else:
                    print(string)

            test_probs = {
            }  # Store the probability of each person getting tested

            # Update each person
            for person in self.people.values():

                # Count susceptibles
                if person.susceptible:
                    self.results['n_susceptible'][t] += 1
                    continue  # Don't bother with the rest of the loop

                # Handle testing probability
                if person.infectious:
                    test_probs[person.uid] = self[
                        'symptomatic']  # They're infectious: high probability of testing
                else:
                    test_probs[person.uid] = 1.0

                # If exposed, check if the person becomes infectious
                if person.exposed:
                    self.results['n_exposed'][t] += 1
                    if not person.infectious and t >= person.date_infectious:  # It's the day they become infectious
                        person.infectious = True
                        if verbose >= 2:
                            print(
                                f'      Person {person.uid} became infectious!'
                            )

                # If infectious, check if anyone gets infected
                if person.infectious:
                    # First, check for recovery
                    if person.date_recovered and t >= person.date_recovered:  # It's the day they become infectious
                        person.exposed = False
                        person.infectious = False
                        person.recovered = True
                        self.results['recoveries'][t] += 1
                    else:
                        self.results['n_infectious'][
                            t] += 1  # Count this person as infectious
                        n_contacts = cv.pt(
                            person.contacts
                        )  # Draw the number of Poisson contacts for this person
                        contact_inds = cv.choose_people(
                            max_ind=len(self.people),
                            n=n_contacts)  # Choose people at random
                        for contact_ind in contact_inds:
                            exposure = cv.bt(self['r_contact']
                                             )  # Check for exposure per person
                            if exposure:
                                target_person = self.people[contact_ind]
                                if target_person.susceptible:  # Skip people who are not susceptible
                                    self.results['infections'][t] += 1
                                    target_person.susceptible = False
                                    target_person.exposed = True
                                    target_person.date_exposed = t
                                    incub_pars = dict(dist='normal_int',
                                                      par1=self['incub'],
                                                      par2=self['incub_std'])
                                    dur_pars = dict(dist='normal_int',
                                                    par1=self['dur'],
                                                    par2=self['dur_std'])
                                    incub_dist = cv.sample(**incub_pars)
                                    dur_dist = cv.sample(**dur_pars)

                                    target_person.date_infectious = t + incub_dist
                                    target_person.date_recovered = target_person.date_infectious + dur_dist
                                    if verbose >= 2:
                                        print(
                                            f'        Person {person.uid} infected person {target_person.uid}!'
                                        )

                # Count people who recovered
                if person.recovered:
                    self.results['n_recovered'][t] += 1

            # Implement testing -- this is outside of the loop over people, but inside the loop over time
            if t < len(
                    daily_tests
            ):  # Don't know how long the data is, ensure we don't go past the end
                n_tests = daily_tests.iloc[t]  # Number of tests for this day
                if n_tests and not pl.isnan(
                        n_tests):  # There are tests this day
                    self.results['tests'][
                        t] = n_tests  # Store the number of tests
                    test_probs = pl.array(list(test_probs.values()))
                    test_probs /= test_probs.sum()
                    test_inds = cv.choose_people_weighted(probs=test_probs,
                                                          n=n_tests)
                    uids_to_pop = []
                    for test_ind in test_inds:
                        tested_person = self.people[test_ind]
                        if tested_person.infectious and cv.bt(
                                self['sensitivity']
                        ):  # Person was tested and is true-positive
                            self.results['diagnoses'][t] += 1
                            tested_person.diagnosed = True
                            if self['evac_positives']:
                                uids_to_pop.append(tested_person.uid)
                            if verbose >= 2:
                                print(
                                    f'          Person {person.uid} was diagnosed!'
                                )
                    for uid in uids_to_pop:  # Remove people from the ship once they're diagnosed
                        self.off_ship[uid] = self.people.pop(uid)

            # Implement quarantine
            if t == self['quarantine']:
                if verbose >= 1:
                    print(f'Implementing quarantine on day {t}...')
                for person in self.people.values():
                    if 'quarantine_eff' in self.pars.keys():
                        quarantine_eff = self['quarantine_eff']  # Both
                    else:
                        if person.crew:
                            quarantine_eff = self['quarantine_eff_c']  # Crew
                        else:
                            quarantine_eff = self['quarantine_eff_g']  # Guests
                    person.contacts *= quarantine_eff

            # Implement testing change
            if t == self['testing_change']:
                if verbose >= 1:
                    print(f'Implementing testing change on day {t}...')
                self['symptomatic'] *= self[
                    'testing_symptoms']  # Reduce the proportion of symptomatic testing

            # Implement evacuations
            if t < len(evacuated):
                n_evacuated = evacuated.iloc[
                    t]  # Number of evacuees for this day
                if n_evacuated and not pl.isnan(
                        n_evacuated
                ):  # There are evacuees this day # TODO -- refactor with n_tests
                    if verbose >= 1:
                        print(f'Implementing evacuation on day {t}')
                    evac_inds = cv.choose_people(max_ind=len(self.people),
                                                 n=n_evacuated)
                    uids_to_pop = []
                    for evac_ind in evac_inds:
                        evac_person = self.people[evac_ind]
                        if evac_person.infectious and cv.bt(
                                self['sensitivity']):
                            self.results['evac_diagnoses'][t] += 1
                        uids_to_pop.append(evac_person.uid)
                    for uid in uids_to_pop:  # Remove people from the ship once they're diagnosed
                        self.off_ship[uid] = self.people.pop(uid)

        # Compute cumulative results
        self.results['cum_exposed'] = pl.cumsum(self.results['infections'])
        self.results['cum_tested'] = pl.cumsum(self.results['tests'])
        self.results['cum_diagnosed'] = pl.cumsum(self.results['diagnoses'])

        # Compute likelihood
        if calc_likelihood:
            self.likelihood()

        # Tidy up
        self.results['ready'] = True
        elapsed = sc.toc(T, output=True)
        if verbose >= 1:
            print(f'\nRun finished after {elapsed:0.1f} s.\n')
            summary = self.summary_stats()
            print(f"""Summary:
     {summary['n_susceptible']:5.0f} susceptible
     {summary['n_exposed']:5.0f} exposed
     {summary['n_infectious']:5.0f} infectious
               """)

        if do_plot:
            self.plot(**kwargs)

        return self.results