def run(scenario: Scenario, data_path: str, reload: bool = False) -> None: reader = Reader(data_path) populations_df = reader.load_csv("populations", orient="dataframe") 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() } lockdown_start, lockdown_end, end, slow_unlock = scenario.get_lockdown_info( ) file_name = scenario.get_spread_model_filename() file_path = os.path.join(data_path, f"{file_name}.pkl") if not os.path.exists(file_path) or reload: worker = functools.partial( run_worker, lockdown_start=lockdown_start, lockdown_end=lockdown_end, end=end, slow_unlock=slow_unlock, data_path=data_path, spread_model_params=scenario.spread_model_params, ) with multiprocessing.Pool() as pool: data = pool.map(worker, [populations_by_region[r] for r in Region]) keys = data[0].keys() data = { k: { t: {r: data[i][k][t] for i, r in enumerate(Region)} for t in range(end) } for k in keys } with open(file_path, "wb") as f: pickle.dump(data, f)
def test_interface( self, corporate_bankruptcy_model_cls, utilisation, primary_inputs, final_use_shortfall_vs_demand, ): reader = Reader(DATA_PATH) state = state_from_utilisation(UTILISATION_NO_COVID_NO_LOCKDOWN) state.gdp_state = IoGdpState( primary_inputs=primary_inputs, final_use_shortfall_vs_demand=final_use_shortfall_vs_demand, ) new_state = advance_state(state, utilisation) new_state.gdp_state = IoGdpState( primary_inputs=primary_inputs, final_use_shortfall_vs_demand=final_use_shortfall_vs_demand, ) cb_model = corporate_bankruptcy_model_cls() cb_model.load(reader) cb_model.simulate(state) cb_model.simulate(new_state) for ( _business_size, mapping, ) in new_state.corporate_state.proportion_solvent.items(): for sector, solvent in mapping.items(): assert 0 <= solvent <= 1
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 test_interface(self, corporate_bankruptcy_model_cls, gdp_discount): reader = Reader(DATA_PATH) cb_model = corporate_bankruptcy_model_cls() cb_model.load(reader) discounts = cb_model.gdp_discount_factor( days_since_lockdown=1, gdp_discount=gdp_discount, ) for discount in discounts.values(): assert 0 <= discount <= 1
def test_interface(self, gdp_model_cls, lockdown, utilisations): reader = Reader(DATA_PATH) gdp_model = gdp_model_cls() gdp_model.load(reader) gdp_model.simulate(time=0, lockdown=lockdown, lockdown_exit_time=0, utilisations=utilisations) assert 0 <= sum( gdp_model.results.gdp[0].values()) <= gdp_model.results.max_gdp
def __init__( self, data_path: str, ): """ Simulator for adaptER-covid19 :param data_path: path to data :type data_path: str """ self.reader = Reader(data_path)
def test_interface(self, personal_bankruptcy_model_cls, utilisation): reader = Reader(DATA_PATH) state = state_from_utilisation(UTILISATION_NO_COVID_NO_LOCKDOWN) new_state = advance_state(state, utilisation) pb_model = personal_bankruptcy_model_cls() pb_model.load(reader) pb_model.simulate(state) pb_model.simulate(new_state) for region in Region: assert 0 <= new_state.personal_state.personal_bankruptcy[ region] <= 1
def test_interface(self, personal_bankruptcy_model_cls, lockdown, gdp_discount): reader = Reader(DATA_PATH) pb_model = personal_bankruptcy_model_cls() pb_model.load(reader) pb_model.simulate( time=0, lockdown=lockdown, corporate_bankruptcy={k: 1 - v for k, v in gdp_discount.items()}, ) for region in Region: assert 0 <= pb_model.results[0][region].personal_bankruptcy <= 1
def _base_lockdown_state(data_path: str) -> float: """ Get proportion of workforce at work during lockdown :param data_path: path to economics data :return: """ reader = Reader(data_path) keyworker = SectorDataSource("keyworker").load(reader) workers = RegionSectorAgeDataSource("workers").load(reader) return sum( keyworker[s] * workers[r, s, a] for r, s, a in itertools.product(Region, Sector, Age) ) / sum(workers.values())
def test_interface(self, gdp_model_cls, utilisation): reader = Reader(DATA_PATH) state = state_from_utilisation(UTILISATION_NO_COVID_NO_LOCKDOWN) gdp_model = gdp_model_cls() gdp_model.load(reader) gdp_model.simulate(state) if issubclass(gdp_model_cls, PiecewiseLinearCobbDouglasGdpModel): # This is required because we need a `capital` param for the C-D model # TODO: make cleaner NaiveCorporateBankruptcyModel().simulate(state) new_state = advance_state(state, utilisation) new_state.previous.personal_state = DUMMY_PERSONAL_STATE gdp_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)
def load(self, reader: Reader) -> None: io_df = reader.load_csv("input_output").set_index("Sector") self.small_cap_cash_buffer = SectorDataSource("smallcap_cash").load( reader) self.large_cap_pct = SectorDataSource("largecap_pct_turnover").load( reader) self.employee_compensation = { Sector[k]: v for k, v in io_df.employee_compensation.to_dict().items() } self.taxes_minus_subsidies = { Sector[k]: v for k, v in io_df.taxes_minus_subsidies.to_dict().items() } self.capital_consumption = { Sector[k]: v for k, v in io_df.capital_consumption.to_dict().items() } outflows = (io_df.employee_compensation + io_df.taxes_minus_subsidies + io_df.capital_consumption) gross_operating_surplus = (io_df.net_operating_surplus + io_df.capital_consumption) lcap_cash_buffer = (gross_operating_surplus * np.array([self.large_cap_pct[s] for s in Sector]) * self.large_cap_cash_surplus_months / 12) sme_factor = np.array([ (self.small_cap_cash_buffer[s] / self.sinc_theta) / 365 * (1 - self.large_cap_pct[s]) for s in Sector ]) sme_cash_buffer = outflows * sme_factor lcap_clipped_cash_buffer = lcap_cash_buffer.apply(lambda x: max(x, 0)) sme_clipped_cash_buffer = sme_cash_buffer.apply(lambda x: max(x, 0)) self.lcap_clipped_cash_buffer = { Sector[k]: v for k, v in lcap_clipped_cash_buffer.to_dict().items() } self.sme_clipped_cash_buffer = { Sector[k]: v for k, v in sme_clipped_cash_buffer.to_dict().items() } value_added = (io_df.net_operating_surplus + io_df.employee_compensation + io_df.taxes_minus_subsidies + io_df.capital_consumption) self.value_added = { Sector[k]: v for k, v in value_added.to_dict().items() }
def state_from_utilisation( utilisation: Utilisation, new_spending_day: int = 10**6, ccff_day: int = 10**6, loan_guarantee_day: int = 10**6, ) -> SimulateState: reader = Reader(DATA_PATH) utilisations = Utilisations( { k: copy.deepcopy(utilisation) for k in itertools.product(Region, Sector, Age) }, reader=reader, ) lambdas = utilisation.to_lambdas() ill = sum(v for k, v in lambdas.items() if k in ILL_STATES) dead = lambdas[WorkerState.DEAD] # Placeholder until quarantine is integrated from the covid model quarantine = 0 ill, dead, quarantine, p_wfh = [{ k: x for k in itertools.product(Region, Sector, Age) } for x in [ill, dead, quarantine, utilisation.p_wfh]] state = SimulateState( time=0, dead=dead, ill=ill, quarantine=quarantine, p_wfh=p_wfh, lockdown=float(utilisation.p_wfh > 0), furlough=utilisation.p_furloughed > 0, new_spending_day=new_spending_day, ccff_day=ccff_day, loan_guarantee_day=loan_guarantee_day, fear_factor_coef_lockdown=1.0, fear_factor_coef_ill=1.0, fear_factor_coef_dead=1.0, utilisations=utilisations, ) return state
def plot_econ_data( model: Economics, total_individuals: int, end_time: int, data_dir: str, results_dir: str, ) -> None: # Time series plot of overall values # Load all necessary data reader = Reader(data_dir) gdp_data = RegionSectorAgeDataSource("gdp").load(reader) gdp_per_sector = { s: sum(gdp_data[r, s, a] for r, a in itertools.product(Region, Age)) for s in Sector } gdp_per_sector = { s: v / sum(gdp_per_sector.values()) for s, v in gdp_per_sector.items() } workers_data = RegionSectorAgeDataSource("gdp").load(reader) workers_per_region = { r: sum(workers_data[r, s, a] for s, a in itertools.product(Sector, Age)) for r in Region } workers_per_region = { r: v / sum(workers_per_region.values()) for r, v in workers_per_region.items() } populations_path = os.path.join(data_dir, "populations.csv") people_per_region = { Region[k]: v for k, v in pd.read_csv(populations_path) .set_index("region") .sum(axis=1) .to_dict() .items() } people_per_region = { r: v / sum(people_per_region.values()) for r, v in people_per_region.items() } gdp = pd.Series( { k: sum(g.values()) / model.results.gdp_result.max_gdp for k, g in model.results.gdp.items() } ) corporate_bankruptcies = 1 - pd.Series( { k: sum(cs[s] * gdp_per_sector[s] for s in Sector) for k, cs in model.results.corporate_solvencies.items() } ) personal_bankruptcies = pd.Series( { k: sum(pb[r].personal_bankruptcy * workers_per_region[r] for r in Region) for k, pb in model.results.personal_bankruptcy.items() } ) epidemic_data = { r: pd.read_csv(os.path.join(results_dir, f"{r.name}_ts.csv")) for r in Region } deaths = pd.Series( { i: sum( epidemic_data[r].loc[i, "n_death"] / total_individuals * people_per_region[r] for r in Region ) for i in range(end_time) } ) recoveries = pd.Series( { i: sum( epidemic_data[r].loc[i, "n_recovered"] / total_individuals * people_per_region[r] for r in Region ) for i in range(end_time) } ) # Plot fig, ax = plt.subplots() gdp.plot(ax=ax, label="gdp") corporate_bankruptcies.plot(ax=ax, label="corporate_bankruptcies") personal_bankruptcies.plot(ax=ax, label="personal_bankruptcies") (deaths * 100).plot(ax=ax, label="deaths * 100") recoveries.plot(ax=ax, label="recoveries") ax.set_xlabel("time / days") ax.legend() # GDP by sectors, area chart gdp_by_sector_path = os.path.join(results_dir, "gdp_by_sector.csv") gdp_by_sector = pd.read_csv(gdp_by_sector_path) fig, ax = plt.subplots() # First sector is special - need to fill between 0 and it ax.fill_between( gdp_by_sector.index, gdp_by_sector.iloc[:, 0] * 0, gdp_by_sector.iloc[:, 0], label=gdp_by_sector.columns[0], ) for i in range(1, gdp_by_sector.shape[1]): ax.fill_between( gdp_by_sector.index, gdp_by_sector.iloc[:, i - 1], gdp_by_sector.iloc[:, i], label=gdp_by_sector.columns[i], ) ax.set_xlabel("Time / days") ax.set_ylabel("GDP / Pre-crisis GDP") ax.legend(ncol=2) # Affect of corporate bankruptcies on GDP, by sector corp_bank_path = os.path.join(results_dir, "corporate_solvencies_sector.csv") corp_bank_df = pd.read_csv(corp_bank_path) fig, ax = plt.subplots() corp_bank_df.plot(ax=ax) # Fraction personal bankruptcies, by sector personal_bank_path = os.path.join(results_dir, "personal_bankruptcies.csv") personal_bank_df = pd.read_csv(personal_bank_path) fig, ax = plt.subplots() personal_bank_df.plot(ax=ax) plt.show()
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)
def test_optimiser(self): reader = Reader(DATA_PATH) model = PiecewiseLinearCobbDouglasGdpModel() model.load(reader) setup = model.setup state = state_from_utilisation(UTILISATION_NO_COVID_NO_LOCKDOWN) def default_soln(v): # print(v) if v[0] == "q": return setup.q_iot[v[1]] elif v[0] == "d": return setup.dtilde_iot.loc[v[1], v[2]] elif v[0] == "x" or v[0] == "xtilde": return setup.xtilde_iot.loc[v[1], v[2]] elif v[0] == "y": return setup.ytilde_total_iot[v[1]] elif v[0] == "lambda": if v[1] == LabourState.WORKING: return 1.0 elif v[1] == LabourState.WFH: return 0.0 elif v[1] == LabourState.ILL: return 0.0 default_solution = [default_soln(v) for v in setup.variables] assert all([v is not None for v in default_solution]) model.simulate(state) assert len(state.gdp_state.primary_inputs) > 1 assert len(state.gdp_state.final_uses) > 1 assert len(state.gdp_state.compensation_received) > 1 assert len(state.gdp_state.compensation_paid) > 1 assert len(state.gdp_state.compensation_subsidy) > 1 res = state.gdp_state._optimise_result x = res.x _df = pd.DataFrame([x, default_solution], columns=setup.variables, index=["found", "default"]).T _df["diff"] = _df["found"] - _df["default"] _df["err %"] = _df["diff"] / _df["default"] _df["var type"] = [v[0] for v in _df.index] _df["var index 1"] = [ v[1] if len(v) >= 2 else np.nan for v in _df.index ] _df["var index 2"] = [ v[2] if len(v) >= 3 else np.nan for v in _df.index ] # found and default final uses should be almost equal when aggregated np.testing.assert_allclose( _df[_df["var type"] == "y"]["found"].sum(), setup.ytilde_total_iot.sum(), rtol=1e-3, atol=0, ) # found and default gdp should be almost equal np.testing.assert_allclose( setup.get_gdp(x).sum(), setup.max_gdp, rtol=1e-3, atol=0, ) # objective fn part 1 (gdp) equals sum of default final uses minus imports np.testing.assert_allclose( np.sum(list(setup.gdp_per_sector.values()), axis=0).dot(res.x), setup.ytilde_total_iot.sum() - setup.xtilde_iot.loc[M.I].sum() - setup.o_iot.loc[PrimaryInput.TAXES_PRODUCTS].sum(), rtol=1e-3, atol=0, ) # objective fn part 1 (gdp) equals sum of default operating surplus np.testing.assert_allclose( np.sum(list(setup.gdp_per_sector.values()), axis=0).dot(res.x), setup.xtilde_iot.loc[M.K].sum() + setup.xtilde_iot.loc[M.L].sum() + setup.o_iot.loc[PrimaryInput.TAXES_PRODUCTION].sum(), rtol=1e-5, atol=0, ) # objective fn part 2 (surplus) equals consumption + net operating surplus np.testing.assert_allclose( np.sum(list(setup.surplus_per_sector.values()), axis=0).dot(res.x), setup.xtilde_iot.loc[M.K].sum(), rtol=1e-5, atol=0, ) # objective fn part 1 + part 2 = objective fn np.testing.assert_allclose( (np.sum(list(setup.gdp_per_sector.values()), axis=0) + np.sum(list(setup.surplus_per_sector.values()), axis=0)).dot( res.x), -res.fun, rtol=1e-5, atol=0, ) # found solution matches default solution for each variable # note: the household sector has lots of zero values, making the optimization problem underconstrained. # therefore, we ignore variables relating to the household sector in below checks __df = _df[~((_df["var index 1"] == Sector.T_HOUSEHOLD) | (_df["var index 2"] == Sector.T_HOUSEHOLD))] np.testing.assert_allclose(__df["found"], __df["default"], rtol=1e-4, atol=1e0) # all non-lambda variables are in currency, therefore large atol is acceptable np.testing.assert_allclose( __df[__df["var type"] != "lambda"]["found"], __df[__df["var type"] != "lambda"]["default"], rtol=1e-8, atol=2e0, ) # all lambda variables are in [0,1] therefore atol has to be small np.testing.assert_allclose( __df[__df["var type"] == "lambda"]["found"], __df[__df["var type"] == "lambda"]["default"], rtol=1e-5, atol=1e-5, )
household_demographics_path = click.format_filename(household_demographics) econ_data_dir = click.format_filename(econ_data_dir) if example_parameters is None: example_parameters = EXAMPLE_PARAMETERS # 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,
def load(self, reader: Reader) -> None: """ Load data required for simulation Parameters ---------- reader: helper class to load data """ # primary inputs data io_df = reader.load_csv("input_output").set_index("Sector") self.employee_compensation = { Sector[k]: v for k, v in io_df.employee_compensation.to_dict().items() } self.taxes_minus_subsidies = { Sector[k]: v for k, v in io_df.taxes_minus_subsidies.to_dict().items() } self.capital_consumption = { Sector[k]: v for k, v in io_df.capital_consumption.to_dict().items() } outflows = ( io_df.employee_compensation + io_df.taxes_minus_subsidies + io_df.capital_consumption ) self.outflows = {Sector[k]: v for k, v in outflows.to_dict().items()} self.net_operating_surplus = { Sector[k]: v for k, v in io_df.net_operating_surplus.apply(lambda x: max(x, 0)) .to_dict() .items() } gross_operating_surplus = ( io_df.net_operating_surplus.apply(lambda x: max(x, 0)) + io_df.capital_consumption ) value_added = ( io_df.net_operating_surplus.apply(lambda x: max(x, 0)) + io_df.employee_compensation + io_df.taxes_minus_subsidies + io_df.capital_consumption ) self.value_added = {Sector[k]: v for k, v in value_added.to_dict().items()} # large cap cash buffer self.large_cap_pct = SectorDataSource("largecap_pct_turnover").load(reader) lcap_cash_buffer = ( gross_operating_surplus * np.array([self.large_cap_pct[s] for s in Sector]) * self.large_cap_cash_surplus_months / 12 ) lcap_clipped_cash_buffer = lcap_cash_buffer.apply(lambda x: max(x, 0)) self.lcap_clipped_cash_buffer = { Sector[k]: v for k, v in lcap_clipped_cash_buffer.to_dict().items() } # sme cash buffer self.sme_cash_buffer_days = SectorDataSource("smallcap_cash").load(reader) sme_factor = np.array( [ (self.sme_cash_buffer_days[s] / self.sinc_theta) / DAYS_IN_A_YEAR * (1 - self.large_cap_pct[s]) for s in Sector ] ) sme_cash_buffer = outflows * sme_factor sme_clipped_cash_buffer = sme_cash_buffer.apply(lambda x: max(x, 0)) self.sme_clipped_cash_buffer = { Sector[k]: v for k, v in sme_clipped_cash_buffer.to_dict().items() } # company demographics self.turnover = reader.load_csv("company_size_and_turnover").set_index("Sector") self.sme_count = { Sector[k]: int(v) for k, v in self.turnover[self.turnover.min_size < 250] .groupby(["Sector"])["num_companies"] .sum() .to_dict() .items() } self.sme_count.update({s: 0 for s in set(Sector) - self.sme_count.keys()}) self.largecap_count = { Sector[k]: int(v) for k, v in self.turnover[self.turnover.min_size >= 250] .groupby(["Sector"])["num_companies"] .sum() .to_dict() .items() } self.largecap_count.update( {s: 0 for s in set(Sector) - self.largecap_count.keys()} ) sme_company_sector_counts = self.turnover[self.turnover.min_size < 250][ ["min_size", "num_companies"] ] self.sme_company_size = { Sector[k]: v for k, v in np.repeat( sme_company_sector_counts.min_size, sme_company_sector_counts.num_companies, ) .groupby(["Sector"]) .apply(lambda x: np.array(x)) .to_dict() .items() } large_company_sector_counts = self.turnover[self.turnover.min_size >= 250][ ["min_size", "num_companies"] ] self.large_company_size = { Sector[k]: v for k, v in np.repeat( large_company_sector_counts.min_size, large_company_sector_counts.num_companies, ) .groupby(["Sector"]) .apply(lambda x: np.array(x)) .to_dict() .items() } self.growth_rates = SectorDataSource("growth_rates").load(reader) self.exhuberance_factor = {s: 1.0 for s in Sector} # simulate initial cash buffers self._init_sim() # vulnerabilities for new spending stimulus sme_vulnerability = reader.load_csv("sme_rate_payer_vulnerability").set_index( "Sector" ) sme_vulnerability /= sme_vulnerability.sum() self.sme_vulnerability = { Sector[k]: v for k, v in sme_vulnerability["vulnerability"].to_dict().items() } # coronavirus business interruption loan scheme (CBILS) stimulus parameters self.loan_guarantee_remaining = 330e3 self.size_loan = { 0: 0.01, 1: 0.05, 2: 0.05, 5: 0.05, 10: 0.25, 20: 0.25, 50: 0.25, 100: 0.25, 200: 0.25, } self.sme_company_received_loan = { s: np.zeros(self.sme_count[s]) for s in Sector }
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))