Пример #1
0
    def validate_pars(self):
        ''' Some parameters can take multiple types; this makes them consistent '''

        # Handle start day
        start_day = self['start_day']  # Shorten
        if start_day in [None, 0]:  # Use default start day
            start_day = dt.datetime(2020, 1, 1)
        if not isinstance(start_day, dt.datetime):
            start_day = sc.readdate(start_day)
        self['start_day'] = start_day  # Convert back

        # Handle population data
        popdata_choices = ['random', 'bayesian', 'data']
        if sc.isnumber(self['usepopdata']) or isinstance(
                self['usepopdata'],
                bool):  # Convert e.g. usepopdata=1 to 'bayesian'
            self['usepopdata'] = popdata_choices[int(
                self['usepopdata'])]  # Choose one of these
        if self['usepopdata'] not in popdata_choices:
            choice = self['usepopdata']
            choicestr = ', '.join(popdata_choices)
            errormsg = f'Population data option "{choice}" not available; choices are: {choicestr}'
            raise ValueError(errormsg)

        # Handle interventions
        self['interventions'] = sc.promotetolist(self['interventions'],
                                                 keepnone=False)

        return
def make_safegraph(sim, mobility_file):
    ''' Create interventions representing SafeGraph data '''

    # Load data.values
    if mobility_file is None:
        fn = safegraph_file
    else:
        fn = mobility_file
    df = pd.read_csv(fn)
    week = df['week']
    w = c = df['p.tot'].values
    # w = df['p.emp'].values
    # c = df['p.cust'].values

    # Do processing
    npts = len(week)
    start_date = sc.readdate(week[0], dateformat='%Y-%m-%d')
    start_day = sim.day(start_date)
    sg_days = start_day + 7 * np.arange(npts)

    # Create interventions
    interventions = [
        cv.clip_edges(days=sg_days, changes=w, layers='w', label='clip_w'),
        cv.clip_edges(days=sg_days, changes=c, layers='c', label='clip_c'),
    ]
    return interventions
Пример #3
0
    def validate_pars(self):
        ''' Some parameters can take multiple types; this makes them consistent '''

        # Handle start day
        start_day = self['start_day'] # Shorten
        if start_day in [None, 0]: # Use default start day
            start_day = dt.date(2020, 1, 1)
        elif sc.isstring(start_day):
            start_day = sc.readdate(start_day)
        if isinstance(start_day,dt.datetime):
            start_day = start_day.date()
        self['start_day'] = start_day

        # Handle contacts
        contacts = self['contacts']
        if sc.isnumber(contacts): # It's a scalar instead of a dict, assume it's all contacts
            self['contacts']    = {'a':contacts}
            self['beta_layers'] = {'a':1.0}

        # Handle population data
        popdata_choices = ['random', 'microstructure', 'synthpops']
        if sc.isnumber(self['pop_type']) or isinstance(self['pop_type'], bool): # Convert e.g. pop_type=1 to 'microstructure'
            self['pop_type'] = popdata_choices[int(self['pop_type'])] # Choose one of these
        if self['pop_type'] not in popdata_choices:
            choice = self['pop_type']
            choicestr = ', '.join(popdata_choices)
            errormsg = f'Population type "{choice}" not available; choices are: {choicestr}'
            raise ValueError(errormsg)

        # Handle interventions
        self['interventions'] = sc.promotetolist(self['interventions'], keepnone=False)

        return
Пример #4
0
def day(obj, *args, start_day=None):
    '''
    Convert a string, date/datetime object, or int to a day (int), the number of
    days since the start day. See also date() and daydiff(). Used primarily via
    sim.day() rather than directly.

    Args:
        obj (str, date, int, or list): convert any of these objects to a day relative to the start day
        args (list): additional days
        start_day (str or date): the start day; if none is supplied, return days since 2020-01-01.

    Returns:
        days (int or str): the day(s) in simulation time

    **Example**::

        sim.day('2020-04-05') # Returns 35
    '''

    # Do not process a day if it's not supplied
    if obj is None:
        return None
    if start_day is None:
        start_day = '2020-01-01'

    # Convert to list
    if sc.isstring(obj) or sc.isnumber(obj) or isinstance(
            obj, (dt.date, dt.datetime)):
        obj = sc.promotetolist(obj)  # Ensure it's iterable
    elif isinstance(obj, np.ndarray):
        obj = obj.tolist()  # Convert to list if it's an array
    obj.extend(args)

    days = []
    for d in obj:
        if d is None:
            days.append(d)
        elif sc.isnumber(d):
            days.append(int(d))  # Just convert to an integer
        else:
            try:
                if sc.isstring(d):
                    d = sc.readdate(d).date()
                elif isinstance(d, dt.datetime):
                    d = d.date()
                d_day = (d - date(start_day)
                         ).days  # Heavy lifting -- actually compute the day
                days.append(d_day)
            except Exception as E:
                errormsg = f'Could not interpret "{d}" as a date: {str(E)}'
                raise ValueError(errormsg)

    # Return an integer rather than a list if only one provided
    if len(days) == 1:
        days = days[0]

    return days
Пример #5
0
    def validate_pars(self):
        ''' Some parameters can take multiple types; this makes them consistent '''

        # Handle types
        for key in ['pop_size', 'pop_infected', 'pop_size', 'n_days']:
            self[key] = int(self[key])

        # Handle start day
        start_day = self['start_day']  # Shorten
        if start_day in [None, 0]:  # Use default start day
            start_day = dt.date(2020, 1, 1)
        elif sc.isstring(start_day):
            start_day = sc.readdate(start_day)
        if isinstance(start_day, dt.datetime):
            start_day = start_day.date()
        self['start_day'] = start_day

        # Handle contacts
        contacts = self['contacts']
        if sc.isnumber(
                contacts
        ):  # It's a scalar instead of a dict, assume it's all contacts
            self['contacts'] = {'a': contacts}

        # Handle key mismaches
        beta_layer_keys = set(self.pars['beta_layer'].keys())
        contacts_keys = set(self.pars['contacts'].keys())
        quar_eff_keys = set(self.pars['quar_eff'].keys())
        if not (beta_layer_keys == contacts_keys == quar_eff_keys):
            errormsg = f'Layer parameters beta={beta_layer_keys}, contacts={contacts_keys}, quar_eff={quar_eff_keys} have inconsistent keys'
            raise cvm.KeyNotFoundError(errormsg)
        if self.people is not None:
            pop_keys = set(self.people.contacts.keys())
            if pop_keys != beta_layer_keys:
                errormsg = f'Please update your parameter keys {beta_layer_keys} to match population keys {pop_keys}. You may find sim.reset_layer_pars() helpful.'
                raise cvm.KeyNotFoundError(errormsg)

        # Handle population data
        popdata_choices = ['random', 'hybrid', 'clustered', 'synthpops']
        choice = self['pop_type']
        if choice not in popdata_choices:
            choicestr = ', '.join(popdata_choices)
            errormsg = f'Population type "{choice}" not available; choices are: {choicestr}'
            raise cvm.KeyNotFoundError(errormsg)

        # Handle interventions
        self['interventions'] = sc.promotetolist(self['interventions'],
                                                 keepnone=False)

        return
    def begin_day(self, date):
        ''' Called at the beginning of each day to configure the school layer '''

        dayname = sc.readdate(date).strftime('%A')
        group = self.schedule[dayname]
        self.school_day = group == 'all'

        # Could modify layer based on group
        if group == 'all':
            # Start with the original layer, will remove uids at home later
            self.layer = sc.dcp(self.base_layer)  # needed?
            uids = self.uids
        else:
            self.layer = cv.Layer()  # Empty
            uids = np.empty(0, dtype='int64')
        return uids  # Everyone is scheduled for school today, unless it's a weekend
Пример #7
0
def date(obj, *args, **kwargs):
    '''
    Convert a string or a datetime object to a date object. To convert to an integer
    from the start day, use sim.date() instead.

    Args:
        obj (str, date, datetime): the object to convert
        args (str, date, datetime): additional objects to convert

    Returns:
        dates (date or list): either a single date object, or a list of them

    **Examples**::

        cv.date('2020-04-05') # Returns datetime.date(2020, 4, 5)
    '''
    # Convert to list
    if sc.isstring(obj) or sc.isnumber(obj) or isinstance(
            obj, (dt.date, dt.datetime)):
        obj = sc.promotetolist(obj)  # Ensure it's iterable
    obj.extend(args)

    dates = []
    for d in obj:
        try:
            if type(
                    d
            ) == dt.date:  # Do not use isinstance, since must be the exact type
                pass
            elif sc.isstring(d):
                d = sc.readdate(d).date()
            elif isinstance(d, dt.datetime):
                d = d.date()
            else:
                errormsg = f'Could not interpret "{d}" of type {type(d)} as a date'
                raise TypeError(errormsg)
            dates.append(d)
        except Exception as E:
            errormsg = f'Conversion of "{d}" to a date failed: {str(E)}'
            raise ValueError(errormsg)

    # Return an integer rather than a list if only one provided
    if len(dates) == 1:
        dates = dates[0]

    return dates
Пример #8
0
    def day(self, day, *args):
        '''
        Convert a string, date/datetime object, or int to a day (int).

        Args:
            day (str, date, int, or list): convert any of these objects to a day relative to the simulation's start day

        Returns:
            days (int or str): the day(s) in simulation time

        **Example**::

            sim.day('2020-04-05') # Returns 35
        '''
        # Do not process a day if it's not supplied
        if day is None:
            return None

        # Convert to list
        if sc.isstring(day) or sc.isnumber(day) or isinstance(
                day, (dt.date, dt.datetime)):
            day = sc.promotetolist(day)  # Ensure it's iterable
        day.extend(args)

        days = []
        for d in day:
            if sc.isnumber(d):
                days.append(int(d))  # Just convert to an integer
            else:
                try:
                    if sc.isstring(d):
                        d = sc.readdate(d).date()
                    elif isinstance(d, dt.datetime):
                        d = d.date()
                    d_day = (d - self['start_day']).days
                    days.append(d_day)
                except Exception as E:
                    errormsg = f'Could not interpret "{d}" as a date: {str(E)}'
                    raise ValueError(errormsg)

        # Return an integer rather than a list if only one provided
        if len(days) == 1:
            days = days[0]

        return days
    def begin_day(self, date):
        ''' Called at the beginning of each day to configure the school layer '''
        dayname = sc.readdate(date).strftime('%A')
        group = self.schedule[dayname]
        self.school_day = group in ['A', 'B']

        # Could modify layer based on group
        if group == 'A':
            self.layer = sc.dcp(self.A_base_layer)  # needed?
            uids = self.A_group
        elif group == 'B':
            self.layer = sc.dcp(self.B_base_layer)  # needed?
            uids = self.B_group
        else:
            uids = np.empty(0, dtype='int64')
            self.layer = cv.Layer()  # Empty

        return uids  # Hybrid scheduling
Пример #10
0
def test_readdate():
    sc.heading('Test string-to-date conversion')

    string1 = '2020-Mar-21'
    string2 = '2020-03-21'
    string3 = 'Sat Mar 21 23:13:56 2020'
    dateobj1 = sc.readdate(string1)
    dateobj2 = sc.readdate(string2)
    sc.readdate(string3)
    assert dateobj1 == dateobj2
    with pytest.raises(ValueError):
        sc.readdate('Not a date')

    # Automated tests
    formats_to_try = sc.readdate(return_defaults=True)
    for key, fmt in formats_to_try.items():
        datestr = sc.getdate(dateformat=fmt)
        dateobj = sc.readdate(datestr, dateformat=fmt)
        print(f'{key:15s} {fmt:22s}: {dateobj}')

    return dateobj1
Пример #11
0
def test_base():
    sc.heading('Testing base.py sim...')

    json_path = 'base_tests.json'
    sim_path = 'base_tests.sim'

    # Create a small sim for later use
    sim = cv.Sim(pop_size=100, verbose=verbose)
    sim.run()

    # Check setting invalid key
    with pytest.raises(sc.KeyNotFoundError):
        po = cv.ParsObj(pars={'a': 2, 'b': 3})
        po.update_pars({'c': 4})

    # Printing result
    r = cv.Result()
    print(r)
    print(r.npts)

    # Day and date conversion
    daystr = '2020-04-04'
    sim.day(daystr)
    sim.day(sc.readdate(daystr))
    with pytest.raises(ValueError):
        sim.day('not a date')
    sim.date(34)
    sim.date([34, 54])
    sim.date(34, 54, as_date=True)

    # BaseSim methods
    sim.copy()
    sim.export_results(filename=json_path)
    sim.export_pars(filename=json_path)
    sim.shrink(in_place=False)
    for keep_people in [True, False]:
        sim.save(filename=sim_path, keep_people=keep_people)
    cv.Sim.load(sim_path)

    # Tidy up
    remove_files(json_path, sim_path)

    return
Пример #12
0
    def validate_pars(self):
        ''' Some parameters can take multiple types; this makes them consistent '''

        # Handle start day
        start_day = self['start_day']  # Shorten
        if start_day in [None, 0]:  # Use default start day
            start_day = dt.date(2020, 1, 1)
        elif sc.isstring(start_day):
            start_day = sc.readdate(start_day)
        if isinstance(start_day, dt.datetime):
            start_day = start_day.date()
        self['start_day'] = start_day

        # Handle contacts
        contacts = self['contacts']
        if sc.isnumber(
                contacts
        ):  # It's a scalar instead of a dict, assume it's all contacts
            self['contacts'] = {'a': contacts}

        # Handle key mismaches
        beta_layer_keys = set(self.pars['beta_layer'].keys())
        contacts_keys = set(self.pars['contacts'].keys())
        quar_eff_keys = set(self.pars['quar_eff'].keys())
        if not (beta_layer_keys == contacts_keys == quar_eff_keys):
            errormsg = f'Layer parameters beta={beta_layer_keys}, contacts={contacts_keys}, quar_eff={quar_eff_keys} are not consistent'
            raise ValueError(errormsg)

        # Handle population data
        popdata_choices = ['random', 'hybrid', 'clustered', 'synthpops']
        choice = self['pop_type']
        if choice not in popdata_choices:
            choicestr = ', '.join(popdata_choices)
            errormsg = f'Population type "{choice}" not available; choices are: {choicestr}'
            raise ValueError(errormsg)

        # Handle interventions
        self['interventions'] = sc.promotetolist(self['interventions'],
                                                 keepnone=False)

        return
def make_safegraph(sim, use_interp=True):
    ''' Create interventions representing SafeGraph data '''

    # Load data.values
    fn = safegraph_file
    df = pd.read_csv(fn)
    week = df['week']
    w = df["p.emp.no.schools"].values
    c = df["p.cust.no.schools"].values
    s = df["p.tot.schools"].values

    # Do processing
    npts = len(week)
    start_date = sc.readdate(week[0], dateformat='%Y-%m-%d')
    start_day = sim.day(start_date)
    sg_days = start_day + 7 * np.arange(npts)

    # Create interventions
    interventions = [
        cv.clip_edges(days=sg_days, changes=w, layers='w', label='clip_w'),
        cv.clip_edges(days=sg_days, changes=c, layers='c', label='clip_c'),
        cv.clip_edges(days=sg_days, changes=s, layers='s', label='clip_s'),
    ]
    return interventions
Пример #14
0
def test_misc():
    sc.heading('Testing miscellaneous functions')

    sim_path = 'test_misc.sim'
    json_path = 'test_misc.json'
    gitinfo_path = 'test_misc.gitinfo'
    fig_path = 'test_misc.png'
    fig_comments = 'Test comment'

    # Data loading
    cv.load_data(csv_file)
    cv.load_data(xlsx_file)

    with pytest.raises(NotImplementedError):
        cv.load_data('example_data.unsupported_extension')

    with pytest.raises(ValueError):
        cv.load_data(xlsx_file, columns=['missing_column'])

    # Dates
    d1 = cv.date('2020-04-04')
    d2 = cv.date(sc.readdate('2020-04-04'))
    ds = cv.date('2020-04-04', d2)
    assert d1 == d2
    assert d2 == ds[0]

    with pytest.raises(ValueError):
        cv.date([(2020, 4, 4)])  # Raises a TypeError which raises a ValueError

    with pytest.raises(ValueError):
        cv.date('Not a date')

    cv.daydiff('2020-04-04')

    # Run sim for more investigations
    sim = cv.Sim(pop_size=500, verbose=0)
    sim.run()
    sim.plot(do_show=False)

    # Saving and loading
    cv.savefig(fig_path, comments=fig_comments)
    cv.save(filename=sim_path, obj=sim)
    cv.load(filename=sim_path)

    # Version checks
    cv.check_version('0.0.0')  # Nonsense version
    print('↑ Should complain about version')
    with pytest.raises(ValueError):
        cv.check_version('0.0.0', die=True)

    # Git checks
    cv.git_info(json_path)
    cv.git_info(json_path, check=True)

    # Poisson tests
    c1 = 5
    c2 = 8
    for alternative in ['two-sided', 'larger', 'smaller']:
        cv.poisson_test(c1, c2, alternative=alternative)
    for method in ['score', 'wald', 'sqrt', 'exact-cond']:
        cv.poisson_test(c1, c2, method=method)

    with pytest.raises(ValueError):
        cv.poisson_test(c1, c2, method='not a method')

    # Test locations
    for location in [None, 'viet-nam']:
        cv.data.show_locations(location)

    # Test versions
    with pytest.raises(ValueError):
        cv.check_save_version('1.3.2', die=True)
    cv.check_save_version(cv.__version__,
                          filename=gitinfo_path,
                          comments='Test')

    # Test PNG
    try:
        metadata = cv.get_png_metadata(fig_path, output=True)
        assert metadata['Covasim version'] == cv.__version__
        assert metadata['Covasim comments'] == fig_comments
    except ImportError as E:
        print(
            f'Cannot test PNG function since pillow not installed ({str(E)}), skipping'
        )

    # Tidy up
    remove_files(sim_path, json_path, fig_path, gitinfo_path)

    return
Пример #15
0
def single_sim_new(end_day='2020-05-10',
                   rand_seed=1,
                   dist='lognormal',
                   par1=10,
                   par2=170):

    pop_type = 'hybrid'
    pop_size = 225000
    pop_scale = 2.25e6 / pop_size
    start_day = '2020-01-27'
    # end_day   = '2020-05-01'   # for calibration plots
    # end_day   = '2020-06-30'  # for projection plots

    pars = {
        'verbose': 0,
        'pop_size': pop_size,
        'pop_infected': 30,  # 300
        'pop_type': pop_type,
        'start_day': start_day,
        'n_days': (sc.readdate(end_day) - sc.readdate(start_day)).days,
        'pop_scale': pop_scale,
        'rescale': True,
        'beta': 0.015,
        'rand_seed': rand_seed,
    }

    sim = cv.Sim(pars, datafile=datafile)

    # Define beta interventions
    b_days = ['2020-03-04', '2020-03-12', '2020-03-23']
    b_ch = sc.objdict()
    b_ch.h = [1.00, 1.10, 1.20]
    b_ch.s = [1.00, 0.00, 0.00]
    b_ch.w = [0.60, 0.40, 0.25]
    b_ch.c = [0.60, 0.40, 0.25]

    # Define testing interventions
    daily_tests = sim.data['new_tests']
    test_kwargs = {
        'quar_test': 0,
        'sensitivity': 1.0,
        'test_delay': 0,
        'loss_prob': 0
    }
    interventions = [
        cv.test_num(daily_tests=daily_tests,
                    symp_test=70,
                    start_day='2020-01-27',
                    end_day=None,
                    swab_delay_dist={
                        'dist': dist,
                        'par1': par1,
                        'par2': par2
                    },
                    **test_kwargs),
    ]

    for lkey, ch in b_ch.items():
        interventions.append(
            cv.change_beta(days=b_days, changes=b_ch[lkey], layers=lkey))

    sim.update_pars(interventions=interventions)

    sim.initialize()

    # Define age susceptibility
    mapping = {
        0: 0.2,
        20: 0.9,
        40: 1.0,
        70: 2.5,
        80: 5.0,
        90: 10.0,
    }

    for age, val in mapping.items():
        sim.people.rel_sus[sim.people.age > age] = val

    return sim
Пример #16
0
        90: 10.0,
    }

    for age, val in mapping.items():
        sim.people.rel_sus[sim.people.age > age] = val

    return sim


if __name__ == "__main__":

    time_num_old = []
    time_num_new = []
    time_num_flat = []
    # 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()
def create_sim(pars=None, use_safegraph=True, label=None, show_intervs=False, people=None, adjust_ORs=False,
               num_pos=None, test_prob=None,
               trace_prob=None, NPI_schools=None, test_freq=None, network_change=False, schedule=None,
               school_start_day=None,
               intervention_start_day=None, ttq_scen=None
               ):
    ''' Create a single simulation for further use '''

    p = sc.objdict(sc.mergedicts(define_pars(which='best', kind='both', use_safegraph=use_safegraph), pars))
    if 'rand_seed' not in p:
        seed = 1
        print(f'Note, could not find random seed in {pars}! Setting to {seed}')
        p['rand_seed'] = seed  # Ensure this exists

    # Basic parameters and sim creation
    pars = {'pop_size': 225e3,
            'pop_scale': 10,
            'pop_type': 'synthpops',
            'pop_infected': p.pop_infected,
            'beta': p.beta,
            'start_day': '2020-02-01',
            'end_day': p['end_day'],
            'rescale': True,
            'rescale_factor': 1.1,
            'verbose': 0.1,
            'rand_seed': p.rand_seed,
            'analyzers': [cv.age_histogram(datafile=age_data_file,
                                           states=['exposed', 'dead', 'tested', 'diagnosed', 'severe'])],
            'beta_layer': dict(h=p.bl_h, s=p.bl_s, w=p.bl_w, c=p.bl_c, l=p.bl_l),
            }

    # If supplied, use an existing people object
    if people:
        popfile = people
    else:
        # Generate the population filename
        n_popfiles = 5
        popfile = popfile_stem + str(pars['rand_seed'] % n_popfiles) + '.ppl'
        popfile_change = popfile_stem_change + str(pars['rand_seed'] % n_popfiles) + '.ppl'

        # Check that the population file exists
        if not os.path.exists(popfile):
            errormsg = f'WARNING: could not find population file {popfile}! Please regenerate first'
            raise FileNotFoundError(errormsg)

    # Create and initialize the sim
    print(f'Creating sim! safegraph={use_safegraph}, seed={p.rand_seed}')
    sim = cv.Sim(pars, label=label, popfile=popfile, load_pop=True,
                 datafile=epi_data_file)  # Create this here so can be used for test numbers etc.

    interventions = []

    # Testing bins
    df = pd.read_csv(age_series_file)
    age_bins = [0, 20, 40, 60, 80, np.inf]
    test_num_subtargs = [ftest_num_subtarg1, ftest_num_subtarg2, ftest_num_subtarg3, ftest_num_subtarg4,
                         ftest_num_subtarg5]
    for ia in range(len(age_bins) - 1):
        label = '{}-{}'.format(age_bins[ia], age_bins[ia + 1] - 1)
        df_ = df[(df['age'] >= age_bins[ia]) & (df['age'] < age_bins[ia + 1])]
        # sum for the dates
        df_ = df_.groupby('date').sum()
        df_['age'] = age_bins[ia]
        df_['datetime'] = [sc.readdate(d) for d in df_.index.values]
        df_ = df_.set_index('datetime')
        # make sure we have all the days we care about
        new_index = pd.date_range(df_.index[0], df_.index[-1], freq='1d')

        df_ = df_.reindex(new_index, fill_value=0.0, method='nearest')
        test_kwargs = dict(daily_tests=df_['new_tests'], quar_test=1.0, test_delay=2, subtarget=test_num_subtargs[ia])
        interventions += [cv.test_num(symp_test=p.tn1, start_day='2020-01-27', end_day='2020-03-23', **test_kwargs,
                                      label='tn1 ' + label)]
        interventions += [cv.test_num(symp_test=p.tn2, start_day='2020-03-24', end_day='2020-04-14', **test_kwargs,
                                      label='tn2 ' + label)]
        interventions += [cv.test_num(symp_test=p.tn3, start_day='2020-04-15', end_day='2020-05-07', **test_kwargs,
                                      label='tn3 ' + label)]
        interventions += [cv.test_num(symp_test=p.tn4, start_day='2020-05-08', end_day='2020-06-04', **test_kwargs,
                                      label='tn4 ' + label)]
        interventions += [cv.test_num(symp_test=p.tn5, start_day='2020-06-17', end_day='2020-06-18', **test_kwargs,
                                      label='tn5 ' + label)]
        interventions += [cv.test_num(symp_test=p.tn6, start_day='2020-06-19', end_day=None, **test_kwargs,
                                      label='tn6 ' + label)]

    # Seed in LTCF
    interventions += [seed_ltcf(days=[15], seeds=[p.lseeds])]

    # Define beta interventions
    b_days = ['2020-03-02',
              '2020-03-12',
              '2020-03-23',
              '2020-04-15',
              '2020-05-08',
              '2020-06-05',
              '2020-06-19'
              ]

    # Home and school beta changes
    interventions += [
        cv.change_beta(days=b_days[1], changes=p.bc_s, layers='s', label="beta_s")
    ]

    # Work and community beta changes
    b_days_wc = np.arange(sim.day(b_days[0]), sim.day(b_days[1]) + 1).tolist() + b_days[2:]
    b_ch_wc = np.linspace(1.0, p.bc_wc1, len(b_days_wc) - 5).tolist() + [p.bc_wc2, p.bc_wc3, p.bc_wc4, p.bc_wc5,
                                                                         p.bc_wc6]

    for lkey in ['w', 'c']:
        interventions += [cv.change_beta(days=b_days_wc, changes=b_ch_wc, layers=lkey, label=f'beta_{lkey}')]

    # LTCF beta change
    b_days_l = np.arange(sim.day(b_days[0]), sim.day(b_days[2]) + 1)
    b_ch_l = np.linspace(1.0, p.bc_lf, len(b_days_l))
    interventions += [cv.change_beta(days=b_days_l, changes=b_ch_l, layers='l', label='beta_l')]
    # sim.people.contacts['c'] = remove_ltcf_community(sim) # Remove community contacts from LTCF

    # Age-based beta changes
    b_age_days = ["2020-05-08", "2020-06-05", "2020-06-19"]
    b_age_changes = [[p.bc_age_u10_a,  # 0
                      p.bc_age_10_20_a,  # 10
                      p.bc_age_20_30_a,  # 20
                      p.bc_age_30_40_a,  # 30
                      1.0,  # 40
                      1.0,  # 50
                      p.bc_age_65u_a,  # 65
                      p.bc_age_65u_a,  # 70
                      p.bc_age_65u_a,  # 80
                      p.bc_age_65u_a,  # 90
                      ],
                     [p.bc_age_u10_b,  # 0
                      p.bc_age_10_20_b,  # 10
                      p.bc_age_20_30_b,  # 20
                      p.bc_age_30_40_b,  # 30
                      1.0,  # 40
                      1.0,  # 50
                      p.bc_age_65u_b,  # 65
                      p.bc_age_65u_b,  # 70
                      p.bc_age_65u_b,  # 80
                      p.bc_age_65u_b,  # 90
                      ],
                     [p.bc_age_u10_c,  # 0
                      p.bc_age_10_20_c,  # 10
                      p.bc_age_20_30_c,  # 20
                      p.bc_age_30_40_c,  # 30
                      1.0,  # 40
                      1.0,  # 50
                      p.bc_age_65u_c,  # 65
                      p.bc_age_65u_c,  # 70
                      p.bc_age_65u_c,  # 80
                      p.bc_age_65u_c,  # 90
                      ]
                     ]
    interventions += [beta_change_age.change_beta_age(b_age_days, b_age_changes)]

    # SafeGraph intervention & tidy up
    if use_safegraph:
        interventions += make_safegraph(sim)

    if ttq_scen == 'lower':
        tp = sc.objdict(
            symp_prob=0.08,
            asymp_prob=0.001,
            symp_quar_prob=0.8,
            asymp_quar_prob=0.1,
            test_delay=2.0,
        )
        ct = sc.objdict(
            trace_probs=0.01,
            trace_time=3.0,
        )
    elif ttq_scen == 'medium':
        tp = sc.objdict(
            symp_prob=0.12,
            asymp_prob=0.0015,
            symp_quar_prob=0.8,
            asymp_quar_prob=0.1,
            test_delay=2.0,
        )
        ct = sc.objdict(
            trace_probs=0.25,
            trace_time=3.0,
        )
    elif ttq_scen == 'upper':
        tp = sc.objdict(
            symp_prob=0.24,
            asymp_prob=0.003,
            symp_quar_prob=0.8,
            asymp_quar_prob=0.1,
            test_delay=2.0,
        )
        ct = sc.objdict(
            trace_probs=0.5,
            trace_time=3.0,
        )

    if ttq_scen is not None:
        interventions += [cv.test_prob(start_day='2020-07-10', **tp), cv.contact_tracing(start_day='2020-07-10', **ct)]

    if network_change:
        popfile_new = popfile_change
    else:
        popfile_new = None

    if NPI_schools is not None:
        interventions += [cv.change_beta(days=sim.day('2020-09-01'), changes=NPI_schools, layers='s')]

    interventions += [cv.close_schools(day_schools_closed='2020-03-12', start_day=school_start_day,
                                        pop_file=popfile_new)]

    interventions += [cv.reopen_schools(start_day=intervention_start_day, num_pos=num_pos, test=test_prob,
                                       trace=trace_prob, ili_prev=0.002, test_freq=test_freq, schedule=schedule)]

    sim['interventions'] = interventions

    # Don't show interventions in plots, there are too many
    for interv in sim['interventions']:
        interv.do_plot = False

    # Prognoses (particularly to severe/hospitalizations) need attention
    prognoses = sc.dcp(cv.get_prognoses())
    prognoses['severe_probs'] *= prognoses[
        'symp_probs']  # Conditional probability of symptoms becoming severe, given symptomatic
    prognoses['crit_probs'] *= prognoses[
        'severe_probs']  # Conditional probability of symptoms becoming critical, given severe
    prognoses['death_probs'] *= prognoses['crit_probs']  # Conditional probability of dying, given critical symptoms
    prognoses.update({'age_cutoff': np.array([0, 10, 20, 30, 40, 50, 65, 70, 80, 90])})
    prognoses.update({'severe_probs': np.array([1, 1, 1, p.rsp1, p.rsp1, p.rsp1, p.rsp1, p.rsp1, p.rsp2, p.rsp2]) *
                                      prognoses['severe_probs']})
    prognoses['death_probs'] /= prognoses['crit_probs']  # Conditional probability of dying, given critical symptoms
    prognoses['crit_probs'] /= prognoses[
        'severe_probs']  # Conditional probability of symptoms becoming critical, given severe
    prognoses['severe_probs'] /= prognoses[
        'symp_probs']  # Conditional probability of symptoms becoming severe, given symptomatic
    sim.pars.update({'prognoses': prognoses})

    return sim
Пример #18
0
def test_base():
    sc.heading('Testing base.py...')

    json_path = 'base_tests.json'
    sim_path = 'base_tests.sim'

    # Create a small sim for later use
    sim = cv.Sim(pop_size=100, verbose=verbose)
    sim.run()

    # Check setting invalid key
    with pytest.raises(sc.KeyNotFoundError):
        po = cv.ParsObj(pars={'a': 2, 'b': 3})
        po.update_pars({'c': 4})

    # Printing result
    r = cv.Result()
    print(r)
    print(r.npts)

    # Day and date conversion
    daystr = '2020-04-04'
    sim.day(daystr)
    sim.day(sc.readdate(daystr))
    with pytest.raises(ValueError):
        sim.day('not a date')
    sim.date(34)
    sim.date([34, 54])
    sim.date(34, 54, as_date=True)

    # BaseSim methods
    sim.copy()
    sim.export_results(filename=json_path)
    sim.export_pars(filename=json_path)
    sim.shrink(in_place=False)
    for keep_people in [True, False]:
        sim.save(filename=sim_path, keep_people=keep_people)
    cv.Sim.load(sim_path)

    # BasePeople methods
    ppl = sim.people
    ppl.get(['susceptible', 'infectious'])
    ppl.keys(which='all_states')
    ppl.index()
    ppl.resize(pop_size=200)
    ppl.to_df()
    ppl.to_arr()
    ppl.person(50)
    people = ppl.to_people()
    ppl.from_people(people)
    with pytest.raises(sc.KeyNotFoundError):
        ppl.make_edgelist([{'invalid_key': [0, 1, 2]}])

    # Contacts methods
    contacts = ppl.contacts
    df = contacts['a'].to_df()
    ppl.remove_duplicates(df)
    with pytest.raises(sc.KeyNotFoundError):
        contacts['invalid_key']
    contacts.values()
    len(contacts)

    # Transmission tree methods
    ppl.transtree.make_targets()
    ppl.make_detailed_transtree()
    ppl.transtree.plot()
    ppl.transtree.animate(animate=False)

    # Tidy up
    remove_files(json_path, sim_path)

    return
Пример #19
0
        90: 10.0,
    }

    for age, val in mapping.items():
        sim.people.rel_sus[sim.people.age > age] = val

    return sim


if __name__ == "__main__":

    time_prob_old = []
    time_prob_new = []
    time_prob_flat = []
    # 2020-05-10 - 2020-01-27
    days = (sc.readdate("2020-05-10") - sc.readdate("2020-01-27")).days + 1
    yield_prob_old = np.zeros(days)
    yield_prob_new = np.zeros(days)
    yield_prob_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 = 11
    n_run = end - start
    for i in range(start, end):
        sim = single_sim_old(rand_seed=i)
        t = sc.tic()
        sim.run()
sim = msim.base_sim
tt = sim.make_transtree()
#tt = sc.loadobj(f'{resfolder}/tt.obj')
layer_keys = list(sim.people.layer_keys())
layer_mapping = {k:i for i,k in enumerate(layer_keys)}
n_layers = len(layer_keys)
colors = sc.gridcolors(n_layers)

layer_counts = np.zeros((sim.npts, n_layers))
for source_ind, target_ind in tt.transmissions:
    dd = tt.detailed[target_ind]
    date = dd['date']
    layer_num = layer_mapping[dd['layer']]
    layer_counts[date, layer_num] += sim.rescale_vec[date]

lockdown1 = [sc.readdate('2020-03-23'),sc.readdate('2020-05-31')]
lockdown2 = [sc.readdate('2020-11-05'),sc.readdate('2020-12-03')]
lockdown3 = [sc.readdate('2021-01-04'),sc.readdate('2021-02-08')]

labels = ['Household', 'School', 'Workplace', 'Community']
for l in range(n_layers):
    ax.plot(sim.datevec, layer_counts[:,l], c=colors[l], lw=3, label=labels[l])
ax.axvspan(lockdown1[0], lockdown1[1], color='steelblue', alpha=0.2, lw=0)
ax.axvspan(lockdown2[0], lockdown2[1], color='steelblue', alpha=0.2, lw=0)
ax.axvspan(lockdown3[0], lockdown3[1], color='lightblue', alpha=0.2, lw=0)
sc.setylim(ax=ax)
sc.boxoff(ax=ax)
ax.set_ylabel('Transmissions per day')
ax.set_xlim([sc.readdate('2020-01-21'), sc.readdate('2021-03-01')])
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b\n%y'))
do_plot = 1
do_save = 1
do_show = 1
verbose = 1
seed = 1

version = 'v1'
date = '2020may26'
folder = f'results_FINAL_{date}'
file_path = f'{folder}/phase_{version}'  # Completed below
data_path = 'UK_Covid_cases_may21.xlsx'
pop_path = f'{file_path}.pop'
fig_path = f'{file_path}.png'
#ig_paths = [f'results/testing_scen_{i}.png' for i in range(3)]

start_day = sc.readdate('2020-01-21')
end_day = sc.readdate('2021-05-31')
n_days = (end_day - start_day).days

# Set the parameters
#quar_eff = 0.8
#quar_effs = {k:quar_eff for k in 'hwsc'}
total_pop = 67.86e6  # UK population size
pop_size = 100e3  # Actual simulated population
ratio = int(total_pop / pop_size)
pop_scale = ratio
pop_type = 'hybrid'
#100% transmissibility of kids also ps=0.0135 for May and June
pop_infected = 4000
#beta=0.00485
beta = 0.007661
Пример #22
0
'''

import sciris as sc
import covasim as cv

intervs1 = [
    cv.change_beta(30, 0.5),
    cv.test_prob(symp_prob=0.1, start_day=20),
    ]

s1 = cv.Sim(start_day='2020-03-01', interventions=intervs1)
s1.run()


intervs2 = [
    cv.change_beta('2020-03-31', 0.5),
    cv.test_prob(symp_prob=0.1, start_day='2020-03-21'),
    ]

s2 = cv.Sim(start_day='2020-03-01', interventions=intervs2)
s2.run()

assert s1.summary == s2.summary

intervs3 = [
    cv.change_beta(days=['2020-03-31', sc.readdate('2020-04-07'), 50], changes=[0.5, 0.3, 0.0]),
    ]

s3 = cv.Sim(start_day='2020-03-01', interventions=intervs3)
s3.run()
s3.plot()
Пример #23
0
def single_sim_old(end_day='2020-05-10', rand_seed=1):

    pop_type = 'hybrid'
    pop_size = 225000
    pop_scale = 2.25e6 / pop_size
    start_day = '2020-01-27'
    # end_day   = '2020-05-01'   # for calibration plots
    # end_day   = '2020-06-30'  # for projection plots

    pars = {
        'verbose': 0,
        'pop_size': pop_size,
        'pop_infected': 30,  # 300
        'pop_type': pop_type,
        'start_day': start_day,
        'n_days': (sc.readdate(end_day) - sc.readdate(start_day)).days,
        'pop_scale': pop_scale,
        'beta': 0.015,
        'rand_seed': rand_seed,
    }

    sim = cv.Sim(pars, datafile=datafile)

    # Define beta interventions
    b_days = ['2020-03-04', '2020-03-12', '2020-03-23']
    b_ch = sc.objdict()
    b_ch.h = [1.00, 1.10, 1.20]
    b_ch.s = [1.00, 0.00, 0.00]
    b_ch.w = [0.60, 0.40, 0.25]
    b_ch.c = [0.60, 0.40, 0.25]

    # Define testing interventions
    test_kwargs = {
        'symp_prob': 0.05,
        'asymp_prob': 0.0008,
        'symp_quar_prob': 0,
        'asymp_quar_prob': 0,
        'test_delay': 0,
        'test_sensitivity': 1.0,
        'loss_prob': 0.0
    }
    interventions = [
        test_prob_old(start_day='2020-01-27', **test_kwargs),
    ]

    for lkey, ch in b_ch.items():
        interventions.append(
            cv.change_beta(days=b_days, changes=b_ch[lkey], layers=lkey))

    sim.update_pars(interventions=interventions)

    sim.initialize()

    # Define age susceptibility
    mapping = {
        0: 0.2,
        20: 0.9,
        40: 1.0,
        70: 2.5,
        80: 5.0,
        90: 10.0,
    }

    for age, val in mapping.items():
        sim.people.rel_sus[sim.people.age > age] = val

    return sim
Пример #24
0
def test_misc():
    sc.heading('Testing miscellaneous functions')

    sim_path = 'test_misc.sim'
    json_path = 'test_misc.json'

    # Data loading
    cv.load_data(csv_file)
    cv.load_data(xlsx_file)

    with pytest.raises(NotImplementedError):
        cv.load_data('example_data.unsupported_extension')

    with pytest.raises(ValueError):
        cv.load_data(xlsx_file, columns=['missing_column'])

    # Dates
    d1 = cv.date('2020-04-04')
    d2 = cv.date(sc.readdate('2020-04-04'))
    ds = cv.date('2020-04-04', d2)
    assert d1 == d2
    assert d2 == ds[0]

    with pytest.raises(ValueError):
        cv.date([(2020, 4, 4)])  # Raises a TypeError which raises a ValueError

    with pytest.raises(ValueError):
        cv.date('Not a date')

    cv.daydiff('2020-04-04')

    # Saving and loading
    sim = cv.Sim()
    cv.save(filename=sim_path, obj=sim)
    cv.load(filename=sim_path)

    # Version checks
    cv.check_version('0.0.0')  # Nonsense version
    print('↑ Should complain about version')
    with pytest.raises(ValueError):
        cv.check_version('0.0.0', die=True)

    # Git checks
    cv.git_info(json_path)
    cv.git_info(json_path, check=True)

    # Poisson tests
    c1 = 5
    c2 = 8
    for alternative in ['two-sided', 'larger', 'smaller']:
        cv.poisson_test(c1, c2, alternative=alternative)
    for method in ['score', 'wald', 'sqrt', 'exact-cond']:
        cv.poisson_test(c1, c2, method=method)

    with pytest.raises(ValueError):
        cv.poisson_test(c1, c2, method='not a method')

    # Tidy up
    remove_files(sim_path, json_path)

    return
def covid_tracking_date_to_date(d):
    ''' Date is in format e.g. 20201031 '''
    out = sc.readdate(str(d))  # Should be a supported format
    return out
Пример #26
0
def plot():
    fig = pl.figure(num='Fig. 2: Transmission dynamics', figsize=(20,14))
    piey, tsy, r3y = 0.68, 0.50, 0.07
    piedx, tsdx, r3dx = 0.2, 0.9, 0.25
    piedy, tsdy, r3dy = 0.2, 0.47, 0.35
    pie1x, pie2x = 0.12, 0.65
    tsx = 0.07
    dispx, cumx, sympx = tsx, 0.33+tsx, 0.66+tsx
    ts_ax   = pl.axes([tsx, tsy, tsdx, tsdy])
    pie_ax1 = pl.axes([pie1x, piey, piedx, piedy])
    pie_ax2 = pl.axes([pie2x, piey, piedx, piedy])
    symp_ax = pl.axes([sympx, r3y, r3dx, r3dy])
    disp_ax = pl.axes([dispx, r3y, r3dx, r3dy])
    cum_ax  = pl.axes([cumx, r3y, r3dx, r3dy])

    off = 0.06
    txtdispx, txtcumx, txtsympx = dispx-off, cumx-off, sympx-off+0.02
    tsytxt = tsy+tsdy
    r3ytxt = r3y+r3dy
    labelsize = 40-wf
    pl.figtext(txtdispx, tsytxt, 'a', fontsize=labelsize)
    pl.figtext(txtdispx, r3ytxt, 'b', fontsize=labelsize)
    pl.figtext(txtcumx,  r3ytxt, 'c', fontsize=labelsize)
    pl.figtext(txtsympx, r3ytxt, 'd', fontsize=labelsize)


    #%% Fig. 2A -- Time series plot

    layer_keys = list(sim.layer_keys())
    layer_mapping = {k:i for i,k in enumerate(layer_keys)}
    n_layers = len(layer_keys)
    colors = sc.gridcolors(n_layers)

    layer_counts = np.zeros((sim.npts, n_layers))
    for source_ind, target_ind in tt.count_transmissions():
        dd = tt.detailed[target_ind]
        date = dd['date']
        layer_num = layer_mapping[dd['layer']]
        layer_counts[date, layer_num] += sim.rescale_vec[date]

    mar12 = cv.date('2020-03-12')
    mar23 = cv.date('2020-03-23')
    mar12d = sim.day(mar12)
    mar23d = sim.day(mar23)

    labels = ['Household', 'School', 'Workplace', 'Community', 'LTCF']
    for l in range(n_layers):
        ts_ax.plot(sim.datevec, layer_counts[:,l], c=colors[l], lw=3, label=labels[l])
    sc.setylim(ax=ts_ax)
    sc.boxoff(ax=ts_ax)
    ts_ax.set_ylabel('Transmissions per day')
    ts_ax.set_xlim([sc.readdate('2020-01-18'), sc.readdate('2020-06-09')])
    ts_ax.xaxis.set_major_formatter(mdates.DateFormatter('%b-%d'))
    ts_ax.set_xticks([sim.date(d, as_date=True) for d in np.arange(0, sim.day('2020-06-09'), 14)])
    ts_ax.legend(frameon=False, bbox_to_anchor=(0.85,0.1))

    color = [0.2, 0.2, 0.2]
    ts_ax.axvline(mar12, c=color, linestyle='--', alpha=0.4, lw=3)
    ts_ax.axvline(mar23, c=color, linestyle='--', alpha=0.4, lw=3)
    yl = ts_ax.get_ylim()
    labely = yl[1]*1.015
    ts_ax.text(mar12, labely, 'Schools close                     ', color=color, alpha=0.9, style='italic', horizontalalignment='center')
    ts_ax.text(mar23, labely, '                   Stay-at-home', color=color, alpha=0.9, style='italic', horizontalalignment='center')


    #%% Fig. 2A inset -- Pie charts

    pre_counts = layer_counts[0:mar12d, :].sum(axis=0)
    post_counts = layer_counts[mar23d:, :].sum(axis=0)
    pre_counts = pre_counts/pre_counts.sum()*100
    post_counts = post_counts/post_counts.sum()*100

    lpre = [
        f'Household\n{pre_counts[0]:0.1f}%',
        f'School\n{pre_counts[1]:0.1f}% ',
        f'Workplace\n{pre_counts[2]:0.1f}%    ',
        f'Community\n{pre_counts[3]:0.1f}%',
        f'LTCF\n{pre_counts[4]:0.1f}%',
    ]

    lpost = [
        f'Household\n{post_counts[0]:0.1f}%',
        f'School\n{post_counts[1]:0.1f}%',
        f'Workplace\n{post_counts[2]:0.1f}%',
        f'Community\n{post_counts[3]:0.1f}%',
        f'LTCF\n{post_counts[4]:0.1f}%',
    ]

    pie_ax1.pie(pre_counts, colors=colors, labels=lpre, **pieargs)
    pie_ax2.pie(post_counts, colors=colors, labels=lpost, **pieargs)

    pie_ax1.text(0, 1.75, 'Transmissions by layer\nbefore schools closed', style='italic', horizontalalignment='center')
    pie_ax2.text(0, 1.75, 'Transmissions by layer\nafter stay-at-home', style='italic', horizontalalignment='center')


    #%% Fig. 2B -- histogram by overdispersion

    # Process targets
    n_targets = tt.count_targets(end_day=mar12)

    # Handle bins
    max_infections = n_targets.max()
    edges = np.arange(0, max_infections+2)

    # Analysis
    counts = np.histogram(n_targets, edges)[0]
    bins = edges[:-1] # Remove last bin since it's an edge
    norm_counts = counts/counts.sum()
    raw_counts = counts*bins
    total_counts = raw_counts/raw_counts.sum()*100
    n_bins = len(bins)
    index = np.linspace(0, 100, len(n_targets))
    sorted_arr = np.sort(n_targets)
    sorted_sum = np.cumsum(sorted_arr)
    sorted_sum = sorted_sum/sorted_sum.max()*100
    change_inds = sc.findinds(np.diff(sorted_arr) != 0)

    pl.set_cmap('Spectral_r')
    sscolors = sc.vectocolor(n_bins)

    width = 1.0
    for i in range(n_bins):
        disp_ax.bar(bins[i], total_counts[i], width=width, facecolor=sscolors[i])
    disp_ax.set_xlabel('Number of transmissions per case')
    disp_ax.set_ylabel('Proportion of transmissions (%)')
    sc.boxoff()
    disp_ax.set_xlim([0.5, 32.5])
    disp_ax.set_xticks(np.arange(0, 32.5, 4))
    sc.boxoff(ax=disp_ax)

    dpie_ax = pl.axes([dispx+0.05, 0.20, 0.2, 0.2])
    trans1 = total_counts[1:3].sum()
    trans2 = total_counts[3:5].sum()
    trans3 = total_counts[5:8].sum()
    trans4 = total_counts[8:].sum()
    labels = [
        f'1-2:\n{trans1:0.0f}%',
        f' 3-4:\n {trans2:0.0f}%',
        f'5-7: \n{trans3:0.0f}%\n',
        f'>7:  \n{trans4:0.0f}%\n',
        ]
    dpie_args = sc.mergedicts(pieargs, dict(labeldistance=1.2)) # Slightly smaller label distance
    dpie_ax.pie([trans1, trans2, trans3, trans4], labels=labels, colors=sscolors[[0,4,7,12]], **dpie_args)


    #%% Fig. 2C -- cumulative distribution function

    rev_ind = 100 - index
    n_change_inds = len(change_inds)
    change_bins = bins[counts>0][1:]
    for i in range(n_change_inds):
        ib = int(change_bins[i])
        ci = change_inds[i]
        ici = index[ci]
        sci = sorted_sum[ci]
        color = sscolors[ib]
        if i>0:
            cim1 = change_inds[i-1]
            icim1 = index[cim1]
            scim1 = sorted_sum[cim1]
            cum_ax.plot([icim1, ici], [scim1, sci], lw=4, c=color)
        cum_ax.scatter([ici], [sci], s=150, zorder=50-i, c=[color], edgecolor='w', linewidth=0.2)
        if ib<=6 or ib in [8, 10, 25]:
            xoff = 5 - 2*(ib==1) + 3*(ib>=10) + 1*(ib>=20)
            yoff = 2*(ib==1)
            cum_ax.text(ici-xoff, sci+yoff, ib, fontsize=18-wf, color=color)
    cum_ax.set_xlabel('Proportion of primary infections (%)')
    cum_ax.set_ylabel('Proportion of transmissions (%)')
    xmin = -2
    ymin = -2
    cum_ax.set_xlim([xmin, 102])
    cum_ax.set_ylim([ymin, 102])
    sc.boxoff(ax=cum_ax)

    # Draw horizontal lines and annotations
    ancol1 = [0.2, 0.2, 0.2]
    ancol2 = sscolors[0]
    ancol3 = sscolors[6]

    i01 = sc.findlast(sorted_sum==0)
    i20 = sc.findlast(sorted_sum<=20)
    i50 = sc.findlast(sorted_sum<=50)
    cum_ax.plot([xmin, index[i01]], [0, 0], '--', lw=2, c=ancol1)
    cum_ax.plot([xmin, index[i20], index[i20]], [20, 20, ymin], '--', lw=2, c=ancol2)
    cum_ax.plot([xmin, index[i50], index[i50]], [50, 50, ymin], '--', lw=2, c=ancol3)

    # Compute mean number of transmissions for 80% and 50% thresholds
    q80 = sc.findfirst(np.cumsum(total_counts)>20) # Count corresponding to 80% of cumulative infections (100-80)
    q50 = sc.findfirst(np.cumsum(total_counts)>50) # Count corresponding to 50% of cumulative infections
    n80, n50 = [sum(bins[q:]*norm_counts[q:]/norm_counts[q:].sum()) for q in [q80, q50]]

    # Plot annotations
    kw = dict(bbox=dict(facecolor='w', alpha=0.9, lw=0), fontsize=20-wf)
    cum_ax.text(2, 3, f'{index[i01]:0.0f}% of infections\ndo not transmit', c=ancol1, **kw)
    cum_ax.text(8, 23, f'{rev_ind[i20]:0.0f}% of infections cause\n80% of transmissions\n(mean: {n80:0.1f} per infection)', c=ancol2, **kw)
    cum_ax.text(14, 53, f'{rev_ind[i50]:0.0f}% of infections cause\n50% of transmissions\n(mean: {n50:0.1f} per infection)', c=ancol3, **kw)


    #%% Fig. 2D -- histogram by date of symptom onset

    # Calculate
    asymp_count = 0
    symp_counts = {}
    minind = -5
    maxind = 15
    for _, target_ind in tt.transmissions:
        dd = tt.detailed[target_ind]
        date = dd['date']
        delta = sim.rescale_vec[date] # Increment counts by this much
        if dd['s']:
            if tt.detailed[dd['source']]['date'] <= date: # Skip dynamical scaling reinfections
                sdate = dd['s']['date_symptomatic']
                if np.isnan(sdate):
                    asymp_count += delta
                else:
                    ind = int(date - sdate)
                    if ind not in symp_counts:
                        symp_counts[ind] = 0
                    symp_counts[ind] += delta

    # Convert to an array
    xax = np.arange(minind-1, maxind+1)
    sympcounts = np.zeros(len(xax))
    for i,val in symp_counts.items():
        if i<minind:
            ind = 0
        elif i>maxind:
            ind = -1
        else:
            ind = sc.findinds(xax==i)[0]
        sympcounts[ind] += val

    # Plot
    total_count = asymp_count + sympcounts.sum()
    sympcounts = sympcounts/total_count*100
    presymp = sc.findinds(xax<=0)[-1]
    colors = ['#eed15b', '#ee943a', '#c3211a']

    asymp_frac = asymp_count/total_count*100
    pre_frac = sympcounts[:presymp].sum()
    symp_frac = sympcounts[presymp:].sum()
    symp_ax.bar(xax[0]-2, asymp_frac, label='Asymptomatic', color=colors[0])
    symp_ax.bar(xax[:presymp], sympcounts[:presymp], label='Presymptomatic', color=colors[1])
    symp_ax.bar(xax[presymp:], sympcounts[presymp:], label='Symptomatic', color=colors[2])
    symp_ax.set_xlabel('Days since symptom onset')
    symp_ax.set_ylabel('Proportion of transmissions (%)')
    symp_ax.set_xticks([minind-3, 0, 5, 10, maxind])
    symp_ax.set_xticklabels(['Asymp.', '0', '5', '10', f'>{maxind}'])
    sc.boxoff(ax=symp_ax)

    spie_ax = pl.axes([sympx+0.05, 0.20, 0.2, 0.2])
    labels = [f'Asymp-\ntomatic\n{asymp_frac:0.0f}%', f' Presymp-\n tomatic\n {pre_frac:0.0f}%', f'Symp-\ntomatic\n{symp_frac:0.0f}%']
    spie_ax.pie([asymp_frac, pre_frac, symp_frac], labels=labels, colors=colors, **pieargs)

    return fig
Пример #27
0
def date(obj, *args, start_date=None, dateformat=None, as_date=True):
    '''
    Convert a string or a datetime object to a date object. To convert to an integer
    from the start day, it is recommended you supply a start date, or use sim.date()
    instead; otherwise, it will calculate the date counting days from 2020-01-01.
    This means that the output of cv.date() will not necessarily match the output
    of sim.date() for an integer input.

    Args:
        obj (str, date, datetime, list, array): the object to convert
        args (str, date, datetime): additional objects to convert
        start_date (str, date, datetime): the starting date, if an integer is supplied
        dateformat (str): the format to return the date in
        as_date (bool): whether to return as a datetime date instead of a string

    Returns:
        dates (date or list): either a single date object, or a list of them

    **Examples**::

        cv.date('2020-04-05') # Returns datetime.date(2020, 4, 5)
        cv.date('2020-04-14', start_date='2020-04-04', as_date=False) # Returns 10
        cv.date([35,36,37], as_date=False) # Returns ['2020-02-05', '2020-02-06', '2020-02-07']
    '''

    if obj is None:
        return None

    # Convert to list and handle other inputs
    if isinstance(obj, np.ndarray):
        obj = obj.tolist()  # If it's an array, convert to a list
    obj = sc.promotetolist(obj)  # Ensure it's iterable
    obj.extend(args)
    if dateformat is None:
        dateformat = '%Y-%m-%d'
    if start_date is None:
        start_date = '2020-01-01'

    dates = []
    for d in obj:
        if d is None:
            dates.append(d)
            continue
        try:
            if type(
                    d
            ) == dt.date:  # Do not use isinstance, since must be the exact type
                pass
            elif sc.isstring(d):
                d = sc.readdate(d).date()
            elif isinstance(d, dt.datetime):
                d = d.date()
            elif sc.isnumber(d):
                if start_date is None:
                    errormsg = f'To convert the number {d} to a date, you must supply start_date'
                    raise ValueError(errormsg)
                d = date(start_date) + dt.timedelta(days=int(d))
            else:
                errormsg = f'Cannot interpret {type(d)} as a date, must be date, datetime, or string'
                raise TypeError(errormsg)
            if as_date:
                dates.append(d)
            else:
                dates.append(d.strftime(dateformat))
        except Exception as E:
            errormsg = f'Conversion of "{d}" to a date failed: {str(E)}'
            raise ValueError(errormsg)

    # Return an integer rather than a list if only one provided
    if len(dates) == 1:
        dates = dates[0]

    return dates
Пример #28
0
def test_base():
    sc.heading('Testing base.py...')

    json_path = 'base_tests.json'
    sim_path  = 'base_tests.sim'

    # Create a small sim for later use
    sim = cv.Sim(pop_size=100, verbose=verbose)
    sim.run()

    # Check setting invalid key
    with pytest.raises(sc.KeyNotFoundError):
        po = cv.ParsObj(pars={'a':2, 'b':3})
        po.update_pars({'c':4})

    # Printing result
    r = cv.Result()
    print(r)
    print(r.npts)

    # Day and date conversion
    daystr = '2020-04-04'
    sim.day(daystr)
    sim.day(sc.readdate(daystr))
    with pytest.raises(ValueError):
        sim.day('not a date')
    sim.date(34)
    sim.date([34, 54])
    sim.date(34, 54, as_date=True)

    # BaseSim methods
    sim.copy()
    sim.export_results(filename=json_path)
    sim.export_pars(filename=json_path)
    sim.shrink(in_place=False)
    for keep_people in [True, False]:
        sim.save(filename=sim_path, keep_people=keep_people)
    cv.Sim.load(sim_path)

    # BasePeople methods
    ppl = sim.people
    ppl.get(['susceptible', 'infectious'])
    ppl.keys()
    ppl.person_keys()
    ppl.state_keys()
    ppl.date_keys()
    ppl.dur_keys()
    ppl.indices()
    ppl._resize_arrays(pop_size=200) # This only resizes the arrays, not actually create new people
    ppl._resize_arrays(pop_size=100) # Change back
    ppl.to_df()
    ppl.to_arr()
    ppl.person(50)
    people = ppl.to_people()
    ppl.from_people(people)
    ppl.make_edgelist([{'new_key':[0,1,2]}])
    ppl.brief()

    # Contacts methods
    contacts = ppl.contacts
    df = contacts['a'].to_df()
    ppl.remove_duplicates(df)
    with pytest.raises(sc.KeyNotFoundError):
        contacts['invalid_key']
    contacts.values()
    len(contacts)
    print(contacts)
    print(contacts['a'])

    # Layer methods
    hospitals_layer = cv.Layer()
    contacts.add_layer(hospitals=hospitals_layer)
    contacts.pop_layer('hospitals')
    df = hospitals_layer.to_df()
    hospitals_layer.from_df(df)

    # Tidy up
    remove_files(json_path, sim_path)

    return