def test_interface( self, gdp_model_cls, personal_bankruptcy_model_cls, corporate_bankruptcy_model_cls, utilisation, ): reader = Reader(DATA_PATH) state = state_from_utilisation(UTILISATION_NO_COVID_NO_LOCKDOWN) econ_model = Economics( gdp_model_cls(), corporate_bankruptcy_model_cls(), personal_bankruptcy_model_cls(), ) econ_model.load(reader) econ_model.simulate(state) new_state = advance_state(state, utilisation) econ_model.simulate(new_state) # Factor of 1.1 is because of the GDP backbone model assert (0 <= sum(new_state.gdp_state.gdp.values()) <= new_state.gdp_state.max_gdp * 1.1) for ( _business_size, mapping, ) in new_state.corporate_state.proportion_solvent.items(): for sector, solvent in mapping.items(): assert 0 <= solvent <= 1 for region in Region: assert 0 <= new_state.personal_state.personal_bankruptcy[ region] <= 1
def test_interface( self, gdp_model_cls, personal_bankruptcy_model_cls, corporate_bankruptcy_model_cls, lockdown, utilisations, ): reader = Reader(DATA_PATH) econ_model = Economics( gdp_model_cls(), corporate_bankruptcy_model_cls(), personal_bankruptcy_model_cls(), ) econ_model.load(reader) try: # Simulation should fail unless we start outside of lockdown econ_model.simulate(time=0, lockdown=lockdown, utilisations=utilisations) except ValueError: if not lockdown: raise else: if lockdown: raise ValueError() assert 0 <= sum( econ_model.results.fraction_gdp_by_sector(0).values()) <= 1
def _econ_worker( queues: Mapping[Region, multiprocessing.Queue], model: Economics, total_individuals: int, end_time: int, output_dir: str, ) -> Economics: utilisations = {} for step in range(end_time): lockdowns = {} for region, queue in queues.items(): step_, results = queue.get() if step != step_: raise ValueError( f"Simulation offset: expected {step}, found {step_}, state: {results}" ) lockdowns[region] = results["lockdown"] # total individuals is measured per region out_of_action = ( results["n_quarantine"] + results["n_hospital"] + results["n_critical"] + results["n_death"] ) utilisations[region] = 1 - out_of_action / total_individuals if len(set(lockdowns.values())) != 1: raise NotImplementedError( f"Model cannot handle selective lockdown by region yet: step={step} lockdowns={lockdowns}" ) lockdown = next(iter(lockdowns.values())) utilisations = { (r, s, a): utilisations[r] for r, s, a in itertools.product(Region, Sector, Age) } model.simulate(step, lockdown, utilisations) _output_econ_data(model, end_time, output_dir) return model
def simulate( self, scenario: Scenario, show_plots: bool = True, figsize: Tuple = (20, 60), scenario_name: str = "", ) -> Tuple[Economics, List[SimulateState]]: """ Run simulation for a given scenario :param scenario: Scenario to run the simulation :type scenario: Scenario :param show_plots: Show the plots using matplotlib if set to be True :type show_plots: bool :param figsize: Size of the figure to be plotted. This parameter is only used when show_plots is set to be True :type figsize: Tuple :param scenario_name: Name of the scenario. Used in plotting :type scenario_name: str :return: Tuple[Economics, List[SimulateState]] """ # Load data for the scenario object if not done yet if not scenario.is_loaded: scenario.load(self.reader) # Initialize various models given the model parameters specified in the Scenario model_params = scenario.model_params gdp_model = PiecewiseLinearCobbDouglasGdpModel( **model_params.gdp_params) cb_model = CorporateBankruptcyModel(**model_params.corporate_params) pb_model = PersonalBankruptcyModel(**model_params.personal_params) econ = Economics(gdp_model, cb_model, pb_model, **model_params.economics_params) # Load data for Economy econ.load(self.reader) states = [] for i in tqdm(range(scenario.simulation_end_time)): # Load ill and dead ratio from scenario ill = scenario.get_ill_ratio_dict(i) dead = scenario.get_dead_ratio_dict(i) # Load quarantine information quarantine = scenario.get_quarantine_ratio_dict(i) # Initialize a SimulateState object simulate_state = scenario.generate( time=i, dead=dead, ill=ill, quarantine=quarantine, lockdown=scenario.lockdown_start_time <= i < scenario.lockdown_end_time, furlough=scenario.furlough_start_time <= i < scenario.furlough_end_time, reader=self.reader, ) # Pass SimulateState to Economy econ.simulate(simulate_state) # Keep a record of the current SimulateState states.append(simulate_state) # Plots if show_plots: fig, axes = plt.subplots(7, 1, sharex="col", sharey="row", figsize=figsize) plot_one_scenario(states, scenario.simulation_end_time, axes, title_prefix=scenario_name) return econ, states
def main( parameters, household_demographics, outdir, total_individuals, lockdown_start, lockdown_end, end_time, econ_data_dir, gdp_model, ) -> None: """ Run simulations by region """ # set up output directory and paths output_dir = click.format_filename(outdir) os.makedirs(output_dir, exist_ok=True) parameters_path = click.format_filename(parameters) household_demographics_path = click.format_filename(household_demographics) econ_data_dir = click.format_filename(econ_data_dir) with open(os.path.join(econ_data_dir, "parameters.json"), "r") as f: econ_parameters = json.load(f) # Read regional population distributions in age populations_df = pd.read_csv(os.path.join(econ_data_dir, "populations.csv")) populations_by_region = { Region[k]: {Age10Y[kk]: vv for kk, vv in v.items()} for k, v in populations_df.set_index("region").T.to_dict().items() } queues = {r: multiprocessing.Queue() for r in Region} # Setup economics model reader = Reader(econ_data_dir) gdp_model = ECON_MODELS[gdp_model](**econ_parameters["gdp"]) cb_model = CorporateBankruptcyModel(**econ_parameters["corporate_bankruptcy"]) pb_model = PersonalBankruptcyModel(**econ_parameters["personal_insolvency"]) econ_model = Economics(gdp_model, cb_model, pb_model) econ_model.load(reader) worker = functools.partial( _worker, output_dir=output_dir, parameters_path=parameters_path, household_demographics_path=household_demographics_path, total_individuals=total_individuals, lockdown_start=lockdown_start, lockdown_end=lockdown_end, end_time=end_time, ) econ_worker = functools.partial( _econ_worker, model=econ_model, total_individuals=total_individuals, end_time=end_time, output_dir=output_dir, ) spread_processes = [ multiprocessing.Process( target=worker, args=((r, populations_by_region[r], queues[r]),) ) for r in Region ] for p in spread_processes: p.start() econ_model = econ_worker(queues) for p in spread_processes: p.join() plot_econ_data(econ_model, total_individuals, end_time, econ_data_dir, output_dir)
# Read regional population distributions in age populations_df = pd.read_csv(os.path.join(econ_data_dir, "populations.csv")) populations_by_region = { Region[k]: {Age10Y[kk]: vv for kk, vv in v.items()} for k, v in populations_df.set_index("region").T.to_dict().items() } manager = multiprocessing.Manager() queues = {r: manager.Queue() for r in Region} # Setup economics model reader = Reader(econ_data_dir) gdp_model = ECON_MODELS[gdp_model](**example_parameters["gdp"]) cb_model = CorporateBankruptcyModel(**example_parameters["corporate_bankruptcy"]) pb_model = PersonalBankruptcyModel(**example_parameters["personal_insolvency"]) econ_model = Economics(gdp_model, cb_model, pb_model) econ_model.load(reader) spread_worker = functools.partial( _spread_worker, output_dir=output_dir, parameters_path=parameters_path, household_demographics_path=household_demographics_path, total_individuals=total_individuals, lockdown_start=lockdown_start, lockdown_end=lockdown_end, end_time=end_time, ) econ_worker = functools.partial( _econ_worker,
def lockdown_then_unlock_no_corona(data_path: str = "data"): """ Lockdown at t=5 days, then release lockdown at t=50 days. :param data_path: :return: """ reader = Reader(data_path) econ = Economics( SupplyDemandGdpModel(), CorporateBankruptcyModel(), PersonalBankruptcyModel() ) econ.load(reader) max_utilisations = {key: 1.0 for key in itertools.product(Region, Sector, Age)} min_utilisations = {key: 0.0 for key in itertools.product(Region, Sector, Age)} length = 100 for i in range(length): if 5 <= i < 50: econ.simulate(i, True, min_utilisations) else: econ.simulate(i, False, max_utilisations) df = ( pd.DataFrame( [econ.results.fraction_gdp_by_sector(i) for i in range(1, length)], index=range(1, length), ) .T.sort_index() .T.cumsum(axis=1) ) # Plot 1 fig, ax = plt.subplots(figsize=(20, 10)) ax.fill_between(df.index, df.iloc[:, 0] * 0, df.iloc[:, 0], label=df.columns[0]) for i in range(1, df.shape[1]): ax.fill_between(df.index, df.iloc[:, i - 1], df.iloc[:, i], label=df.columns[i]) ax.legend(ncol=2) # Plot 2 df = pd.DataFrame( [ econ.results.corporate_solvencies[i] for i in econ.results.corporate_solvencies ] ) df.plot(figsize=(20, 10)) # Plot 3 pd.DataFrame( [ { r: econ.results.personal_bankruptcy[i][r].personal_bankruptcy for r in Region } for i in econ.results.personal_bankruptcy ] ).plot(figsize=(20, 10)) # Plot 4 pd.DataFrame( [ { r: econ.results.personal_bankruptcy[i][r].corporate_bankruptcy for r in Region } for i in econ.results.personal_bankruptcy ] ).plot(figsize=(20, 10))