# Replication package for "The Distributional Effects of COVID-19 and Optimal Mitigation Policies"

Sewon Hur, *International Economic Review*, 2023.

This package contains the model code (Fortran), the analysis code (Matlab and
Stata), the raw data, and the model output needed to reproduce every figure and
table in the paper. Because the optimal-policy analysis solves 3,800 policy
configurations on a computing cluster, the package ships the model output
(`results/`) so that **all figures and tables can be reproduced on a desktop
without re-running the cluster step**. The Fortran code and job scripts used
for the cluster runs are included for completeness.

## Directory structure

```
├── run_01.m               Matlab: model figures, Table 3-5 inputs, results/model*.xls
├── run_02_figures.do      Stata:  model-vs-data figures (Figs. 1-3)
├── run_03_optimality.do   Stata:  optimal-policy figures (Figs. 5-6), Tables 5-7 configs
├── auxiliary/             Matlab helper functions (third party, see below);
│                          Stata intermediate .dta files are written here
├── raw/                   raw data (see Data availability below)
├── results/               model output produced by the Fortran code
│   ├── baseline/<config>/     transition output per policy configuration
│   ├── nopandemic/            no-pandemic counterfactual
│   ├── results<0-10>.csv      optimal-policy grid summaries (0=no pandemic,
│   │                          1=baseline, 2-10=sensitivity; see table below)
│   └── model<N>.xls          model time series used by run_02 (written by run_01)
├── figures/               output folder for generated figures
└── src/
    ├── main/              Fortran source, main model (baseline + sensitivities 0-9)
    ├── replace/           Fortran source, sensitivity 10 (deceased replaced by newborns)
    └── cluster/           SLURM scripts + job list + gather.f90 (cluster runs only)
```

## Computational requirements

* **Fortran** (only needed to re-solve the model): gfortran (tested with GNU
  Fortran 15.2 on macOS/arm64) or Intel Fortran (`make FC=ifort`). No external
  libraries. A single steady state solves in seconds warm-started (~minutes
  cold); a single transition solves in ~5-10 minutes warm-started (hours cold).
  The full optimal-policy grid (3,800 configurations) was run on 800 cores on a
  SLURM cluster (see `src/cluster/`); it is **not** needed to reproduce the
  paper, since its output is included as `results/results*.csv`.
* **Matlab** (figures and table inputs): tested with R2025b. No toolboxes.
* **Stata** (figures and table configurations): tested with Stata/MP 19.5.
  No user-written packages.

## Instructions: reproducing the figures and tables

Run everything from the package root.

1. **Matlab — model figures and table inputs** (`run_01.m`)
   * `jobnum = 1`, `projects = [2 3 4 5]` → prints the model inputs for
     **Tables 3 and 4** to the console; `projects = [2 9 6 7 8]` → prints the
     inputs for **Table 5**. (The Table 3 block prints whenever the first
     project is loaded.)
   * `projects = [2]` → **Figure 4** panels (`oc_*_base_2`, `oh_*_base_2`,
     `tran_disease_age_base_2`).
   * `projects = [2 3]` also rewrites `results/model1.xls`, the model time
     series used by `run_02_figures.do` (**Figure 3** model lines).
2. **Stata — data figures** (`run_02_figures.do`): produces **Figures 1, 2,
   and 3** (`subsidy_1`, `lockdown_1`, `betae_1`, `output_1`, `consumption_1`,
   `outsidecons_1`, `outsidehours_1`, `infections_1`, `deaths_1`,
   `dfrac_age_1`). Requires `results/model1.xls` (included).
3. **Stata — optimal-policy figures and tables** (`run_03_optimality.do`):
   produces **Figures 5-6** (`welf_subsidy_duration_1`,
   `poswelf_subsidy_duration_1`, `deaths_subsidy_duration_1`,
   `output_subsidy_duration_1`, `tauc_subsidy_duration_1`, `hours_subsidy_1`,
   `output_lives_lockdown_1`) and lists the policy configurations reported in
   **Table 5** (baseline, `jobnum 1`) and **Tables 6-7** (sensitivities,
   set `local jobnums = "0 1 2 3 4 5 6 7 8 9 10"`).

Tables 1 and 2 (calibration) are parameter listings; their values appear in
`src/main/parameters.f90` and in `results/baseline/*/PARAMS_MATLAB.out`.

## Instructions: re-solving the model (optional)

```sh
cd src/main && make          # builds covid.exe (gfortran; make FC=ifort for Intel)
```

`covid.exe` run without arguments presents a menu: `11` reads data and builds
grids, `21` solves the pre-pandemic steady state, `411` solves the pandemic
transition for the configuration set in `parameters.f90`; `00` quits. Outputs
are written to the working directory in the same formats as `results/`.

* With `readvguess = 1` (default) the steady state warm-starts from `vss.out`
  and the transition warm-starts from `trans_sol.out` and `vhati.out`; copy
  these from the relevant `results/baseline/<config>/` folder into the working
  directory first. (Note: if `vss.out` is missing, the Fortran `OPEN` creates
  an empty file and the read fails with an end-of-file error — copy the guess
  files first, or set `readvguess = 0` in `parameters.f90` to cold-start.)
* The policy configuration is selected by flags at the top of
  `parameters.f90` (`policy`, `policy2`, `lockdown`, `taxtype`); defaults
  correspond to `baseline/us_policy`.
* Sensitivity experiments (the `results<N>.csv` numbering used by
  `run_03_optimality.do`):

  | N | experiment | change in `parameters.f90` (src/main) |
  |---|---|---|
  | 0 | no pandemic | `inf_init = 0` |
  | 1 | baseline | (defaults) |
  | 2 | subsidy funded by tax on labor income | `taxtype = 2` |
  | 3 | higher value of statistical life | `vsltype = 2` |
  | 4 | smaller efficiency loss during infection | `sick_eta_loss = 0.3` |
  | 5 | no hospital-capacity constraint | `capcon = 0` |
  | 6 | subsidy funded by tax on outside consumption | `taxtype = 3` |
  | 7 | higher inside consumption (gamma = 0.61) | `highgam = 1` |
  | 8 | lower disutility of not working (u-tilde 0.82 -> 0.61) | `non_util_loss` (see the robustness appendix of the paper) |
  | 9 | higher basic reproduction number | `highrepnum = 1` |
  | 10 | deceased replaced by newborns | use `src/replace/` |

* The cluster layer (`src/cluster/`) runs `covid.exe <runmode>` where
  `<runmode>` indexes the policy grid (subsidy level x curvature x lockdown x
  duration); `jobfile` lists all runs, `multinode.slurm` submits them via the
  TACC-style launcher, and `gather/gather.f90` collects the per-run outputs
  into `results<N>.csv`.

## Data availability and provenance

All raw data are publicly available. The package includes the extracts used in
the paper (downloaded 2020-2021):

| file | contents | source |
|---|---|---|
| `raw/daily.csv` | Google Community Mobility Reports (workplaces, retail & recreation, parks); OpenTable seated-diner reservations (YoY); daily COVID-19 deaths and cases (Our World in Data); hours worked by hourly employees (Homebase) | Google LLC "Google COVID-19 Community Mobility Reports"; OpenTable "State of the Industry"; Our World in Data; Homebase |
| `raw/monthly.csv` | total nonfarm employment (BLS CES); average weekly hours, total private (BLS); real PCE (BEA); personal saving rate (BEA); COVID-19 deaths by age (CDC) | BLS; BEA; CDC provisional COVID-19 death counts |
| `raw/quarterly.csv` | real GDP and real consumption (BEA NIPA) | BEA. (Blue Chip consensus forecast columns present in the working dataset were removed here because they are proprietary; they were not used in any published exhibit.) |

Third-party code in `auxiliary/`: `gini.m` (Yvan Lengwiler), `weightedcorrs.m`
(F. Pozzi, T. Di Matteo, T. Aste), `wprctile.m` (Durga Lal Shrestha) — Matlab File Exchange, BSD licenses;
author attributions are in the file headers.

## Notes

* **Portability.** The published results were produced with Intel Fortran on
  Windows/Linux. For this package the source was made compiler-portable
  (gfortran and ifort): removed the Intel-only `IFPORT` module and replaced
  `DCLOCK` with a `SYSTEM_CLOCK` wrapper; declared the `bisection` dummy
  function `PURE` instead of `ELEMENTAL`; replaced integer `IF (flag)` tests
  with `IF (flag /= 0)`; added missing commas in several `FORMAT` statements;
  and renumbered file unit 5 to 25 (unit 5 is stdin under gfortran). None of
  these changes affect numerical output: the gfortran build reproduces the
  archived steady-state output bit-for-bit and the transition output to
  solver precision (max relative difference ~1e-7). In `run_01.m`, figure
  export was migrated from `hgexport` (removed in Matlab R2025b) to
  `exportgraphics` via the `export_pdf` helper at the bottom of the script;
  fonts are fixed at 12pt as in the original export options.
* The per-configuration transition outputs for sensitivities 2-10 (used only
  for unreported diagnostics) are omitted to keep the package size manageable;
  they can be regenerated with `src/main/` and the flag table above.
