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)
Esempio n. 2
0
 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
Esempio n. 3
0
 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
Esempio n. 4
0
 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
Esempio n. 6
0
 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
Esempio n. 7
0
    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)
Esempio n. 8
0
 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
Esempio n. 9
0
 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
Esempio n. 10
0
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())
Esempio n. 11
0
 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()
     }
Esempio n. 13
0
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
Esempio n. 14
0
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()
Esempio n. 15
0
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)
Esempio n. 16
0
    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,
Esempio n. 18
0
    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
        }
Esempio n. 19
0
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))