How Much Should a Region Spend on Disaster Preparedness?
Floods and earthquakes destroy houses and factories. Every turn, a planner must decide how much of the budget goes to prevention, how much to stockpiles, and how much to keep as repair materials. In this article I build a small simulation of this problem, optimize the budget split, and look at the result.
1. Problem Setup
A region starts with the following state.
| Item | Symbol | Initial value |
|---|---|---|
| Population | $P_0$ | 100 |
| Housing capacity | $H_0$ | 130 |
| Production capacity | $K_0$ | 70 |
Each turn, output is limited by labor and production capacity:
$$Y_t = \min\left(K_t,\ \lambda P_t\right), \qquad \lambda = 0.6$$
A fixed share of output becomes the budget:
$$B_t = s,Y_t, \qquad s = 0.25$$
The budget is split into four uses.
| Share | Use | Effect |
|---|---|---|
| $a$ | Disaster defenses (levees, seismic retrofits) | Reduce damage |
| $b$ | Relief stockpile (food, water, tents) | Reduces deaths among the homeless |
| $c$ | Repair materials | Used to rebuild after a disaster |
| $d = 1-a-b-c$ | Growth investment | Adds housing and production capacity |
A parameter $w$ decides which assets get the repair materials first: a share $w$ goes to housing and $1-w$ to production facilities.
Stocks and depreciation. Defenses $D_t$, relief supplies $S_t$, and repair materials $M_t$ decay a little each turn:
$$D_{t+1} = 0.97,D_t + a B_t,\quad S_{t+1} = 0.95,S_t + b B_t,\quad M_{t+1} = 0.98,M_t + c B_t$$
Disasters. A flood occurs with probability 0.15 per turn and an earthquake with probability 0.04. Each has a random intensity $u \in [0.3, 1]$. Defenses reduce the damage rate with diminishing returns:
$$\delta^{F} = 0.45,u_F\left(1 - 0.85\left(1 - e^{-D/30}\right)\right),\qquad \delta^{E} = 0.70,u_E\left(1 - 0.60\left(1 - e^{-D/50}\right)\right)$$
Combined, the fraction of assets lost is
$$\phi = 1 - (1-\delta^{F})(1-\delta^{E})$$
Housing falls by $\phi H$ and production capacity by $0.8,\phi K$. The lost amount becomes repair debt, which repair materials can rebuild. Direct deaths are $P,(0.04,\delta^{F} + 0.12,\delta^{E})$.
Homeless people. People without a home number $\max(0, P - H)$. They need supplies, and unmet needs raise mortality:
$$\text{mortality} = 0.01 + 0.08\times(\text{unmet share of needs})$$
Recovery. Population grows by up to 2.5% per turn, limited by free housing.
Objective. The goal is to choose $(a, b, c, w)$ to maximize the expected cumulative population:
$$\max_{a,b,c,w}\ \ \mathbb{E}\left[\sum_{t=1}^{20} P_t\right]$$
The expectation is estimated by Monte Carlo over random disaster scenarios, and optimized with differential evolution, a global optimizer that needs no gradients.
2. Source Code
The simulator advances all scenarios at once with NumPy arrays instead of looping over scenarios. This makes the optimizer run in a few seconds.
1 | import time |
3. Code Walkthrough
Parameters (Section 1)
All constants live at the top, so you can change the disaster frequency or damage level and rerun. FLOOD_MAX and QUAKE_MAX cap how much defenses can help: even a very large investment cannot erase damage entirely.
Scenario generation (Section 2)
make_scenarios draws a Bernoulli event (flood or earthquake) for every scenario and turn, then multiplies it by a uniform intensity in $[0.3, 1]$. The result is two arrays of shape (n_scenarios, T). Two independent sets are created:
train(1,500 scenarios) is used inside the optimizer.test(5,000 scenarios) is used only for the final comparison.
Evaluating on scenarios the optimizer never saw avoids overstating the benefit of the optimal plan.
The simulator (Section 3)
The state variables (P, H, K, D, S, M, Hd, Kd) are NumPy arrays with one entry per scenario. Each turn performs these steps:
- Production and budget. Output is
min(K, LABOR * P), and a fixed share becomes the budgetB. - Stock updates. Defenses, relief supplies, and repair materials decay and then receive their share of the budget. Growth investment is split equally between housing and production capacity.
- Repairs. Materials are sent first to the assets that the parameter $w$ prioritizes. Any leftover material is used on the other asset. Repaired assets reduce the repair debt
HdandKd. - Disasters. The defense stock determines the damage reduction through $1 - e^{-D/\text{scale}}$. Housing and production capacity are reduced, and the loss is added to the repair debt.
- Homelessness and relief. People beyond housing capacity are homeless. They consume relief supplies, and the unmet share raises their mortality.
- Recovery. Population grows at up to 2.5%, but only into free housing.
Because every operation uses np.minimum, np.maximum, and array arithmetic, there is only one Python loop over the 20 turns. This is the speed-up: a naive version would loop over scenarios as well, which would be roughly 1,500 times slower per evaluation.
Parameter decoding (decode)
The optimizer works in the unit cube $[0,1]^4$. The function converts these to valid shares:
$$a = x_0,\quad b = (1-a),x_1,\quad c = (1-a-b),x_2$$
This guarantees $a + b + c \le 1$ without needing explicit constraints.
Optimization (Section 4)
differential_evolution evolves a population of candidate allocations. It handles the non-smooth min/max structure and the noisy Monte Carlo objective well. polish=False skips the final gradient-based refinement, which is unhelpful for a noisy objective.
Strategy comparison (Section 5)
Four strategies are evaluated on the same 5,000 test scenarios:
- No disaster spend: everything goes to growth.
- Reactive only: 30% goes to repair materials and nothing to prevention.
- Balanced: a hand-made mix of all four.
- Optimized: the optimizer’s answer.
The disaster-free benchmark (no disasters at all) gives an upper bound on what any strategy can reach.
3D surface scan (Section 6)
With $b$ and $w$ fixed at their optimal values, the code scans a $25 \times 25$ grid of defense share $a$ and repair-material share $c$. Cells where $a + b + c > 1$ are masked out, which is why the contour plot is triangular.
4. Execution Results
Optimization time: 9.7 s === Optimal allocation === Defense a=0.453 | Relief stock b=0.004 | Repair materials c=0.346 | Growth d=0.197 Share of repair materials to housing w=1.000 === Cumulative population over 20 turns (5,000 test scenarios) === Strategy Mean P10 P90 No disaster spend 2186.8 1684.8 2591.6 Reactive only 2192.4 1693.6 2589.0 Balanced 2310.8 1857.6 2604.7 Optimized 2432.8 2079.5 2610.2 Disaster-free benchmark (growth-only spend): 2618.3 Improvement over 'No disaster spend': 11.3% Grid scan time: 1.5 s

5. Reading the Results
Optimal allocation
The optimizer found a clear pattern:
| Use | Share |
|---|---|
| Defenses $a$ | about 45% |
| Relief stockpile $b$ | almost 0% |
| Repair materials $c$ | about 35% |
| Growth investment $d$ | about 20% |
| Housing share of repair materials $w$ | about 100% |
Three points stand out.
Prevention and repair work together. About 80% of the budget goes to defenses and repair materials, while growth gets only about 20%. Putting everything into growth is poor because a single large disaster erases years of expansion.
Housing comes first. The optimum sends nearly all repair materials to housing. The reason is the homelessness penalty: a person without a home dies at a higher rate and cannot be supported by population growth, while lost production capacity only reduces the budget. Rebuilding houses protects the population directly.
Relief stockpiles are almost unused. In this model, defenses and fast rebuilding keep the number of homeless people small, so large stockpiles are rarely drawn on. This depends on the parameters: if rebuilding were slow or homelessness widespread, $b$ would rise.
Strategy comparison
| Strategy | Mean | 10th percentile | 90th percentile |
|---|---|---|---|
| No disaster spend | 2186.8 | 1684.8 | 2591.6 |
| Reactive only | 2192.4 | 1693.6 | 2589.0 |
| Balanced | 2310.8 | 1857.6 | 2604.7 |
| Optimized | 2432.8 | 2079.5 | 2610.2 |
The optimized plan improves the mean by about 11.3% over spending nothing on disasters, and it lifts the 10th percentile by more than 20%. The gain is therefore concentrated in the bad scenarios, which is what preparedness is for. The disaster-free benchmark is about 2618, so the optimized plan recovers most of the gap between the unprepared case and a world with no disasters.
Spending only on repair materials (“Reactive only”) barely helps. Without defenses, damage is large and materials are used up quickly.
Figure guide
- Population trajectory (top left). The unprepared region’s lower band drifts below the starting population after repeated disasters, while the optimized path grows steadily and its band stays above 100.
- Cumulative population bars (top right). Mean values rise from left to right, and the black dots (10th percentile) rise even faster, showing improved worst-case protection.
- 3D surface (middle left). The surface is a smooth hill. Too little defense leaves the region exposed; too much starves growth and repair. The red dot marks the peak.
- Contour view (middle right). The same hill seen from above. The high plateau is fairly wide, which means the plan is robust: allocations near the optimum perform almost as well.
- Outcome distribution (bottom left). Without preparation, outcomes spread to the left with a long tail of poor scenarios. The optimized histogram is concentrated near the best outcomes.
- 3D trajectories (bottom right). Forty scenarios sorted from worst to best. Even the worst runs under the optimized plan avoid collapse, and most climb steadily.
6. Conclusion
In this model, a balanced allocation of roughly 45% to defenses, 35% to repair materials, and 20% to growth maximizes the expected 20-turn cumulative population, with nearly all repair materials directed to housing. The main lesson is that disaster spending is not a cost that competes with growth. It protects the very assets that growth builds, and its biggest payoff appears in the worst scenarios.
To extend the model, you could add more disaster types, make rebuilding speed depend on budget, or let the allocation change over time as a policy rather than a constant.









