{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# COVID-19: Healthcare Facility Capacity Optimization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Objective and Prerequisites\n", "\n", "This COVID-19 Healthcare Facility Capacity Optimization problem shows you how to determine the optimal location and capacity of healthcare facilities in order to:\n", "\n", "* Satisfy demand from COVID-19 patients for treatment,\n", "* Minimize the cost of opening temporary facilities for healthcare providers, and\n", "* Predict the allocation of COVID-19 patients from a specific county to a specific healthcare facility.\n", "\n", "This modeling example is at the beginner level, where we assume that you know Python and that you have some knowledge of how to build mathematical optimization models.\n", "\n", "**Download the Repository**
\n", "You can download the repository containing this and other examples by clicking [here](https://github.com/Gurobi/modeling-examples/archive/master.zip). " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Problem Description\n", "\n", "Hospitals in various counties throughout the US are reaching full capacity due to a surge in COVID-19 patients. Many hospitals are considering creating temporary facilities to increase their capacity to handle COVID-19 patients.\n", "\n", "![temporary facility](covid19-trailerFacilty.jpg)\n", "\n", "In this example, we focus on nine counties in the US. Each county has existing facilities to treat COVID-19 patients, and also has the option of building temporary facilities to increase the overall capacity to handle COVID-19 patients.\n", "\n", "The following table defines the coordinates of the centroid and the forecasted demand (i.e. the projected number of COVID-19 patients) of each county. To estimate this demand, we consider the population of nine fictional counties in California, the current number of COVID-19 cases per day in California, the average percentage of COVID-19 cases who require hospitalization, and the average number of days that a COVID-19 patient stays in the hospital.\n", "\n", "| Centroid | Coordinates | Demand |\n", "| --- | --- | --- |\n", "| county 1 | (1, 1.5) | 351 |\n", "| county 2 | (3, 1) | 230 |\n", "| county 3 | (5.5, 1.5) | 529 |\n", "| county 4 | (1, 4.5 ) | 339 |\n", "| county 5 | (3, 3.5) | 360 |\n", "| county 6 | (5.5, 4.5) | 527 |\n", "| county 7 | (1, 8) | 469 |\n", "| county 8 | (3, 6) | 234 |\n", "| county 9 | (4.5, 8) | 500 |\n", "\n", "The following table defines the coordinates and capacity of existing facilities. The capacity of existing facilities is calculated as 80% of the forecasted demand of the county in which the existing facilities are located. The exception to this is county 9, where we assume that we have an excess of existing capacity.\n", "\n", "| Existing | Coordinates | Capacity |\n", "| --- | --- | --- |\n", "| facility 1 | (1, 2) | 281 |\n", "| facility 2 | (2.5, 1) | 187 |\n", "| facility 3 | (5, 1) | 200 |\n", "| facility 4 | (6.5, 3.5) | 223 |\n", "| facility 5 | (1, 5) | 281 |\n", "| facility 6 | (3, 4) | 281 |\n", "| facility 7 | (5, 4) | 222 |\n", "| facility 8 | (6.5, 5.5) | 200 |\n", "| facility 9 | (1, 8.5) | 250 |\n", "| facility 10 | (1.5, 9.5) | 125 |\n", "| facility 11 | (8.5, 6) | 187 |\n", "| facility 12 | (5, 8) | 300 |\n", "| facility 13 | (3, 9) | 300 |\n", "| facility 14 | (6, 9) | 243 |\n", "\n", "The following table defines the coordinates and capacity of new temporary facilities. The cost of building a temporary facility\n", "with a capacity of treating one hundred COVID-19 patients is $\\$500,000$.\n", "\n", "| Temporary | Coordinates | Capacity |\n", "| --- | --- | --- |\n", "| facility 15 | (1.5, 1) | 100 |\n", "| facility 16 | (3.5, 1.5) | 100 |\n", "| facility 17 | (5.5, 2.5) | 100 |\n", "| facility 18 | (1.5, 3.5) | 100 |\n", "| facility 19 | (3.5, 2.5) | 100 |\n", "| facility 20 | (4.5, 4.5) | 100 |\n", "| facility 21 | (1.5, 6.5) | 100 |\n", "| facility 22 | (3.5, 6.5) | 100 |\n", "| facility 23 | (5.5, 6.5) | 100 |\n", "\n", "The coordinates of the three tables are in tens of miles. We assume that each increase of 10 miles in the distance to a COVID-19 facility results in a $\\$5$ increase in driving costs for each COVID-19 patient.\n", "\n", "In this example, the goal is to identify which temporary facilities to build in order to be able to accommodate demand for treatment by COVID-19 patients while minimizing the total cost of COVID-19 patients driving to an existing or temporary COVID-19 facility and the total cost of building temporary facilities.\n", "\n", "This example shows how a Facility Location mixed-integer programming (MIP) model can help healthcare providers make decisions about:\n", "\n", "* How to best utilize their capacity, \n", "* Whether to build temporary facilities for COVID-19 patients, and\n", "* How COVID-19 patients from a county should be allocated to various healthcare facilities in order to ensure that the facilities have the capacity to provide treatment for the patients.\n", "\n", "This Jupyter Notebook is based on the paper written by Katherine Klise and Michael Bynum [1]." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Model Formulation\n", "\n", "### Sets and Indices\n", "\n", "$e \\in E$: Index and set of existing healthcare facility locations.\n", "\n", "$t \\in T$: Index and set of temporary healthcare facility locations.\n", "\n", "$f \\in F = E \\cup T$: Index and set of all healthcare facility locations.\n", "\n", "$c \\in C$: Index and set of counties.\n", "\n", "### Parameters\n", "\n", "$Dist_{c,f} \\in \\mathbb{R}^+$: Distance between county $c$ and facility location $f$.\n", "\n", "$Dem_{c} \\in \\mathbb{R}^+$: Expected number of people in county $c$ who will need a COVID-19 facility.\n", "\n", "$Cap_{f} \\in \\mathbb{R}^+$: Number of people that can be served by a facility at location $f$.\n", "\n", "$\\text{dCost} = 5$: Cost of driving 10 miles.\n", "\n", "$\\text{tFCost} = 500,000$: Cost of building a temporary COVID-19 facility with a capacity of treating 100 COVID-19 patients.\n", "\n", "$bigM$: Penalty of adding extra capacity at temporary facilities in order to satisfy treatment of COVID-19 patients demand.\n", "\n", "### Decision Variables\n", "\n", "$y_{t} \\in \\{0, 1 \\}$: This variable is equal to 1 if we build a temporary facility at location $t$; and 0 otherwise.\n", "\n", "$ x_{c,f} \\in \\mathbb{R}^+$: Number of people from county $c$ served by a facility at location $f$.\n", "\n", "$z_{t} \\in \\mathbb{R}^+$: Extra capacity added at temporary facility location $t$.\n", "\n", "\n", "### Objective Function\n", "\n", "- **Cost**. We want to minimize the total cost of patients driving from a county to a healthcare facility and the total cost of building temporary COVID-19 treatment capacity. The last term with the big penalty coefficient ($bigM$), enables extra capacity to be added at a temporary facility to ensure that total demand is satisfied.\n", " \n", "\n", "\\begin{equation}\n", "\\text{Min} \\quad Z = \\sum_{c \\in C} \\sum_{f \\in F} \\text{dCost} *Dist_{c,f} * x_{c,f} + \n", "\\text{tFCost}*\\sum_{t \\in T} y_{t} + bigM*\\sum_{t \\in T} z_{t}\n", "\\tag{0}\n", "\\end{equation}\n", "\n", "### Constraints\n", "\n", "- **Demand**. Satisfy county demand of service from a COVID-19 facility.\n", "\n", "\\begin{equation}\n", "\\sum_{f \\in F} x_{c,f} = Dem_{c} \\quad \\forall c \\in C\n", "\\tag{1}\n", "\\end{equation}\n", "\n", "- **Existing facilities**. Capacity of an existing location of a facility cannot be exceeded.\n", "\n", "\\begin{equation}\n", "\\sum_{c \\in C} x_{c,e} \\leq Cap_{e} \\quad \\forall e \\in E\n", "\\tag{2}\n", "\\end{equation}\n", "\n", "- **Temporary facilities**. Capacity of a temporary location of a facility cannot be exceeded. Please observe that extra capacity can be added.\n", "\n", "\\begin{equation}\n", "\\sum_{c \\in C} x_{c,t} \\leq Cap_{t}*y_{t} + z_{t} \\quad \\forall t \\in T\n", "\\tag{3}\n", "\\end{equation}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Python Implementation\n", "\n", "We now import the Gurobi Python Module and other Python libraries." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pip install gurobipy" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from itertools import product\n", "from math import sqrt\n", "\n", "import gurobipy as gp\n", "from gurobipy import GRB\n", "\n", "# tested with Gurobi v9.1.0 and Python 3.7.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "### Helper Functions\n", "\n", "* `compute_distance` computes distance between a county centroid and the location of a facility\n", "* `solve_covid19_facility` builds, solves, and prints results of the COVID-19 healthcare facility capacity optimization model" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def compute_distance(loc1, loc2):\n", " \n", " # This function determines the Euclidean distance between a facility and a county centroid.\n", " \n", " dx = loc1[0] - loc2[0]\n", " dy = loc1[1] - loc2[1]\n", " return sqrt(dx*dx + dy*dy)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def solve_covid19_facility(c_coordinates, demand):\n", " \n", " #####################################################\n", " # Data\n", " #####################################################\n", " \n", " # Indices for the counties\n", " counties = [*range(1,10)]\n", " \n", " # Indices for the facilities\n", " facilities = [*range(1,24)]\n", " \n", " # Create a dictionary to capture the coordinates of an existing facility and capacity of treating COVID-19 patients\n", " \n", " existing, e_coordinates, e_capacity = gp.multidict({\n", " 1: [(1, 2), 281],\n", " 2: [(2.5, 1), 187],\n", " 3: [(5, 1), 200],\n", " 4: [(6.5, 3.5), 223],\n", " 5: [(1, 5), 281],\n", " 6: [(3, 4), 281],\n", " 7: [(5, 4), 222],\n", " 8: [(6.5, 5.5), 200],\n", " 9: [(1, 8.5), 250], \n", " 10: [(1.5, 9.5), 125],\n", " 11: [(8.5, 6), 187],\n", " 12: [(5, 8), 300],\n", " 13: [(3, 9), 300],\n", " 14: [(6, 9), 243]\n", " })\n", " \n", " # Create a dictionary to capture the coordinates of a temporary facility and capacity of treating COVID-19 patients\n", " \n", " temporary, t_coordinates, t_capacity = gp.multidict({\n", " 15: [(1.5, 1), 100],\n", " 16: [(3.5, 1.5), 100],\n", " 17: [(5.5, 2.5), 100],\n", " 18: [(1.5, 3.5), 100],\n", " 19: [(3.5, 2.5), 100],\n", " 20: [(4.5, 4.5), 100],\n", " 21: [(1.5, 6.5), 100],\n", " 22: [(3.5, 6.5), 100],\n", " 23: [(5.5, 6.5), 100]\n", " })\n", " \n", " # Cost of driving 10 miles\n", " dcost = 5\n", " \n", " # Cost of building a temporary facility with capacity of 100 COVID-19\n", " tfcost = 500000\n", " \n", " # Compute key parameters of MIP model formulation\n", " f_coordinates = {}\n", " for e in existing:\n", " f_coordinates[e] = e_coordinates[e]\n", " \n", " for t in temporary:\n", " f_coordinates[t] = t_coordinates[t]\n", " \n", " # Cartesian product of counties and facilities\n", " cf = []\n", " \n", " for c in counties:\n", " for f in facilities:\n", " tp = c,f\n", " cf.append(tp)\n", " \n", " # Compute distances between counties centroids and facility locations\n", " distance = {(c,f): compute_distance(c_coordinates[c], f_coordinates[f]) for c, f in cf}\n", " \n", " #####################################################\n", " # MIP Model Formulation\n", " #####################################################\n", " \n", " m = gp.Model('covid19_temporary_facility_location')\n", " \n", " # Build temporary facility\n", " y = m.addVars(temporary, vtype=GRB.BINARY, name='temporary')\n", " \n", " # Assign COVID-19 patients of county to facility\n", " x = m.addVars(cf, vtype=GRB.CONTINUOUS, name='Assign')\n", " \n", " # Add capacity to temporary facilities\n", " z = m.addVars(temporary, vtype=GRB.CONTINUOUS, name='addCap' )\n", " \n", " # Objective function: Minimize total distance to drive to a COVID-19 facility\n", " \n", " # Big penalty for adding capacity at a temporary facility\n", " bigM = 1e9\n", " \n", " m.setObjective(gp.quicksum(dcost*distance[c,f]*x[c,f] for c,f in cf) \n", " + tfcost*y.sum()\n", " + bigM*z.sum(), GRB.MINIMIZE)\n", " \n", " # Counties demand constraints\n", " demandConstrs = m.addConstrs((gp.quicksum(x[c,f] for f in facilities) == demand[c] for c in counties), \n", " name='demandConstrs')\n", " \n", " # Existing facilities capacity constraints\n", " existingCapConstrs = m.addConstrs((gp.quicksum(x[c,e] for c in counties) <= e_capacity[e] for e in existing ), \n", " name='existingCapConstrs')\n", " \n", " # temporary facilities capacity constraints\n", " temporaryCapConstrs = m.addConstrs((gp.quicksum(x[c,t] for c in counties) -z[t] \n", " <= t_capacity[t]*y[t] for t in temporary ),\n", " name='temporaryCapConstrs')\n", " # Run optimization engine\n", " m.optimize()\n", " \n", " #####################################################\n", " # Output Reports\n", " #####################################################\n", " \n", " # Total cost of building temporary facility locations\n", " temporary_facility_cost = 0\n", " \n", " print(f\"\\n\\n_____________Optimal costs______________________\")\n", " for t in temporary:\n", " if (y[t].x > 0.5):\n", " temporary_facility_cost += tfcost*round(y[t].x)\n", " \n", " patient_allocation_cost = 0\n", " for c,f in cf:\n", " if x[c,f].x > 1e-6:\n", " patient_allocation_cost += dcost*round(distance[c,f]*x[c,f].x)\n", " \n", " print(f\"The total cost of building COVID-19 temporary healhtcare facilities is ${temporary_facility_cost:,}\") \n", " print(f\"The total cost of allocating COVID-19 patients to healtcare facilities is ${patient_allocation_cost:,}\") \n", " \n", " # Build temporary facility at location\n", " \n", " print(f\"\\n_____________Plan for temporary facilities______________________\")\n", " for t in temporary:\n", " if (y[t].x > 0.5):\n", " print(f\"Build a temporary facility at location {t}\")\n", " \n", " # Extra capacity at temporary facilities\n", " print(f\"\\n_____________Plan to increase Capacity at temporary Facilities______________________\")\n", " for t in temporary:\n", " if (z[t].x > 1e-6):\n", " print(f\"Increase temporary facility capacity at location {t} by {round(z[t].x)} beds\")\n", "\n", " # Demand satisfied at each facility\n", " f_demand = {}\n", " \n", " print(f\"\\n_____________Allocation of county patients to COVID-19 healthcare facility______________________\")\n", " for f in facilities:\n", " temp = 0\n", " for c in counties:\n", " allocation = round(x[c,f].x)\n", " if allocation > 0:\n", " print(f\"{allocation} COVID-19 patients from county {c} are treated at facility {f} \")\n", " temp += allocation\n", " f_demand[f] = temp\n", " print(f\"{temp} is the total number of COVID-19 patients that are treated at facility {f}. \")\n", " print(f\"\\n________________________________________________________________________________\")\n", " \n", " # Test total demand = total demand satisfied by facilities\n", " total_demand = 0\n", " \n", " for c in counties:\n", " total_demand += demand[c]\n", " \n", " demand_satisfied = 0\n", " for f in facilities:\n", " demand_satisfied += f_demand[f]\n", " \n", " print(f\"\\n_____________Test demand = supply______________________\")\n", " print(f\"Total demand is: {total_demand:,} patients\")\n", " print(f\"Total demand satisfied is: {demand_satisfied:,} beds\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Base Scenario\n", "\n", "In this scenario, we consider the data described for the instance of the COVID-19 Healthcare Facility Capacity Optimization problem. The forecasted demand is as defined in the first table of the problem description." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using license file c:\\gurobi\\gurobi.lic\n", "Gurobi Optimizer version 9.1.0 build v9.1.0rc0 (win64)\n", "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n", "Optimize a model with 32 rows, 225 columns and 432 nonzeros\n", "Model fingerprint: 0xbb38e066\n", "Variable types: 216 continuous, 9 integer (9 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+02]\n", " Objective range [3e+00, 1e+09]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+02, 5e+02]\n", "Presolve time: 0.00s\n", "Presolved: 32 rows, 225 columns, 432 nonzeros\n", "Variable types: 216 continuous, 9 integer (9 binary)\n", "\n", "Root relaxation: objective 1.317174e+06, 58 iterations, 0.00 seconds\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 1317174.01 0 3 - 1317174.01 - - 0s\n", "H 0 0 2020218.8911 1317174.01 34.8% - 0s\n", "H 0 0 1522423.0545 1317174.01 13.5% - 0s\n", "H 0 0 1522032.8389 1317174.01 13.5% - 0s\n", " 0 0 1317555.15 0 4 1522032.84 1317555.15 13.4% - 0s\n", "H 0 0 1521653.4243 1317555.15 13.4% - 0s\n", " 0 0 1317573.07 0 5 1521653.42 1317573.07 13.4% - 0s\n", " 0 0 1317780.47 0 3 1521653.42 1317780.47 13.4% - 0s\n", " 0 0 1318123.14 0 3 1521653.42 1318123.14 13.4% - 0s\n", " 0 2 1318123.14 0 3 1521653.42 1318123.14 13.4% - 0s\n", "\n", "Cutting planes:\n", " Gomory: 6\n", " MIR: 7\n", "\n", "Explored 134 nodes (729 simplex iterations) in 0.08 seconds\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 4: 1.52165e+06 1.52203e+06 1.52242e+06 2.02022e+06 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 1.521653424311e+06, best bound 1.521653424311e+06, gap 0.0000%\n", "\n", "\n", "_____________Optimal costs______________________\n", "The total cost of building COVID-19 temporary healhtcare facilities is $1,500,000\n", "The total cost of allocating COVID-19 patients to healtcare facilities is $21,645\n", "\n", "_____________Plan for temporary facilities______________________\n", "Build a temporary facility at location 15\n", "Build a temporary facility at location 17\n", "Build a temporary facility at location 18\n", "\n", "_____________Plan to increase Capacity at temporary Facilities______________________\n", "\n", "_____________Allocation of county patients to COVID-19 healthcare facility______________________\n", "281 COVID-19 patients from county 1 are treated at facility 1 \n", "281 is the total number of COVID-19 patients that are treated at facility 1. \n", "\n", "________________________________________________________________________________\n", "187 COVID-19 patients from county 2 are treated at facility 2 \n", "187 is the total number of COVID-19 patients that are treated at facility 2. \n", "\n", "________________________________________________________________________________\n", "200 COVID-19 patients from county 3 are treated at facility 3 \n", "200 is the total number of COVID-19 patients that are treated at facility 3. \n", "\n", "________________________________________________________________________________\n", "223 COVID-19 patients from county 3 are treated at facility 4 \n", "223 is the total number of COVID-19 patients that are treated at facility 4. \n", "\n", "________________________________________________________________________________\n", "281 COVID-19 patients from county 4 are treated at facility 5 \n", "281 is the total number of COVID-19 patients that are treated at facility 5. \n", "\n", "________________________________________________________________________________\n", "281 COVID-19 patients from county 5 are treated at facility 6 \n", "281 is the total number of COVID-19 patients that are treated at facility 6. \n", "\n", "________________________________________________________________________________\n", "6 COVID-19 patients from county 3 are treated at facility 7 \n", "50 COVID-19 patients from county 5 are treated at facility 7 \n", "166 COVID-19 patients from county 6 are treated at facility 7 \n", "222 is the total number of COVID-19 patients that are treated at facility 7. \n", "\n", "________________________________________________________________________________\n", "200 COVID-19 patients from county 6 are treated at facility 8 \n", "200 is the total number of COVID-19 patients that are treated at facility 8. \n", "\n", "________________________________________________________________________________\n", "250 COVID-19 patients from county 7 are treated at facility 9 \n", "250 is the total number of COVID-19 patients that are treated at facility 9. \n", "\n", "________________________________________________________________________________\n", "125 COVID-19 patients from county 7 are treated at facility 10 \n", "125 is the total number of COVID-19 patients that are treated at facility 10. \n", "\n", "________________________________________________________________________________\n", "161 COVID-19 patients from county 6 are treated at facility 11 \n", "161 is the total number of COVID-19 patients that are treated at facility 11. \n", "\n", "________________________________________________________________________________\n", "28 COVID-19 patients from county 8 are treated at facility 12 \n", "272 COVID-19 patients from county 9 are treated at facility 12 \n", "300 is the total number of COVID-19 patients that are treated at facility 12. \n", "\n", "________________________________________________________________________________\n", "94 COVID-19 patients from county 7 are treated at facility 13 \n", "206 COVID-19 patients from county 8 are treated at facility 13 \n", "300 is the total number of COVID-19 patients that are treated at facility 13. \n", "\n", "________________________________________________________________________________\n", "228 COVID-19 patients from county 9 are treated at facility 14 \n", "228 is the total number of COVID-19 patients that are treated at facility 14. \n", "\n", "________________________________________________________________________________\n", "57 COVID-19 patients from county 1 are treated at facility 15 \n", "43 COVID-19 patients from county 2 are treated at facility 15 \n", "100 is the total number of COVID-19 patients that are treated at facility 15. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 16. \n", "\n", "________________________________________________________________________________\n", "100 COVID-19 patients from county 3 are treated at facility 17 \n", "100 is the total number of COVID-19 patients that are treated at facility 17. \n", "\n", "________________________________________________________________________________\n", "13 COVID-19 patients from county 1 are treated at facility 18 \n", "58 COVID-19 patients from county 4 are treated at facility 18 \n", "29 COVID-19 patients from county 5 are treated at facility 18 \n", "100 is the total number of COVID-19 patients that are treated at facility 18. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 19. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 20. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 21. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 22. \n", "\n", "________________________________________________________________________________\n", "0 is the total number of COVID-19 patients that are treated at facility 23. \n", "\n", "________________________________________________________________________________\n", "\n", "_____________Test demand = supply______________________\n", "Total demand is: 3,539 patients\n", "Total demand satisfied is: 3,539 beds\n" ] } ], "source": [ "# Create a dictionary to capture the coordinates of a county and the demand of COVID-19 treatment\n", "\n", "counties, coordinates, forecast = gp.multidict({\n", " 1: [(1, 1.5), 351],\n", " 2: [(3, 1), 230],\n", " 3: [(5.5, 1.5), 529],\n", " 4: [(1, 4.5 ), 339],\n", " 5: [(3, 3.5), 360],\n", " 6: [(5.5, 4.5), 527],\n", " 7: [(1, 8), 469],\n", " 8: [(3, 6), 234],\n", " 9: [(4.5, 8), 500] \n", "})\n", "\n", "\n", "# find the optimal solution of the base scenario\n", "solve_covid19_facility(coordinates, forecast)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Analysis for Base Scenario\n", "\n", "The optimal total cost of building COVID-19 temporary healthcare facilities is $\\$1,500,000$, and three COVID-19 temporary healthcare facilities are built. The total cost of allocating COVID-19 patients to healthcare facilities is $\\$21,645$, and no extra capacity needs to be added to accommodate the demand for treatment from COVID-19 patients.\n", "\n", "The MIP model also determines the expected number of COVID-19 patients of a county allocated to a healthcare facility. For example, 6 COVID-19 patients from county 3, 50 COVID-19 patients from county 5, and 166 COVID-19 patients from county 6 are expected to be treated at facility 7. The total number of COVID-19 patients expected to be treated at facility 7 is 222. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Scenario 1 \n", "\n", "Assume that the Centers for Disease Control and Prevention (CDC) announced that the number of hospitalizations will increase by 20%. This percentage includes 5% of buffer capacity to account for the variability of the expected demand." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Gurobi Optimizer version 9.1.0 build v9.1.0rc0 (win64)\n", "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n", "Optimize a model with 32 rows, 225 columns and 432 nonzeros\n", "Model fingerprint: 0x599a0475\n", "Variable types: 216 continuous, 9 integer (9 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+02]\n", " Objective range [3e+00, 1e+09]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+02, 6e+02]\n", "Presolve time: 0.00s\n", "Presolved: 32 rows, 225 columns, 432 nonzeros\n", "Variable types: 216 continuous, 9 integer (9 binary)\n", "\n", "Root relaxation: objective 6.700453e+10, 51 iterations, 0.00 seconds\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", "* 0 0 0 6.700453e+10 6.7005e+10 0.00% - 0s\n", "\n", "Explored 0 nodes (51 simplex iterations) in 0.02 seconds\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 1: 6.70045e+10 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 6.700452551331e+10, best bound 6.700452551331e+10, gap 0.0000%\n", "\n", "\n", "_____________Optimal costs______________________\n", "The total cost of building COVID-19 temporary healhtcare facilities is $4,500,000\n", "The total cost of allocating COVID-19 patients to healtcare facilities is $25,520\n", "\n", "_____________Plan for temporary facilities______________________\n", "Build a temporary facility at location 15\n", "Build a temporary facility at location 16\n", "Build a temporary facility at location 17\n", "Build a temporary facility at location 18\n", "Build a temporary facility at location 19\n", "Build a temporary facility at location 20\n", "Build a temporary facility at location 21\n", "Build a temporary facility at location 22\n", "Build a temporary facility at location 23\n", "\n", "_____________Plan to increase Capacity at temporary Facilities______________________\n", "Increase temporary facility capacity at location 15 by 40 beds\n", "Increase temporary facility capacity at location 17 by 27 beds\n", "\n", "_____________Allocation of county patients to COVID-19 healthcare facility______________________\n", "281 COVID-19 patients from county 1 are treated at facility 1 \n", "281 is the total number of COVID-19 patients that are treated at facility 1. \n", "\n", "________________________________________________________________________________\n", "187 COVID-19 patients from county 2 are treated at facility 2 \n", "187 is the total number of COVID-19 patients that are treated at facility 2. \n", "\n", "________________________________________________________________________________\n", "200 COVID-19 patients from county 3 are treated at facility 3 \n", "200 is the total number of COVID-19 patients that are treated at facility 3. \n", "\n", "________________________________________________________________________________\n", "223 COVID-19 patients from county 3 are treated at facility 4 \n", "223 is the total number of COVID-19 patients that are treated at facility 4. \n", "\n", "________________________________________________________________________________\n", "281 COVID-19 patients from county 4 are treated at facility 5 \n", "281 is the total number of COVID-19 patients that are treated at facility 5. \n", "\n", "________________________________________________________________________________\n", "281 COVID-19 patients from county 5 are treated at facility 6 \n", "281 is the total number of COVID-19 patients that are treated at facility 6. \n", "\n", "________________________________________________________________________________\n", "74 COVID-19 patients from county 3 are treated at facility 7 \n", "148 COVID-19 patients from county 6 are treated at facility 7 \n", "222 is the total number of COVID-19 patients that are treated at facility 7. \n", "\n", "________________________________________________________________________________\n", "200 COVID-19 patients from county 6 are treated at facility 8 \n", "200 is the total number of COVID-19 patients that are treated at facility 8. \n", "\n", "________________________________________________________________________________\n", "250 COVID-19 patients from county 7 are treated at facility 9 \n", "250 is the total number of COVID-19 patients that are treated at facility 9. \n", "\n", "________________________________________________________________________________\n", "125 COVID-19 patients from county 7 are treated at facility 10 \n", "125 is the total number of COVID-19 patients that are treated at facility 10. \n", "\n", "________________________________________________________________________________\n", "187 COVID-19 patients from county 6 are treated at facility 11 \n", "187 is the total number of COVID-19 patients that are treated at facility 11. \n", "\n", "________________________________________________________________________________\n", "300 COVID-19 patients from county 9 are treated at facility 12 \n", "300 is the total number of COVID-19 patients that are treated at facility 12. \n", "\n", "________________________________________________________________________________\n", "188 COVID-19 patients from county 7 are treated at facility 13 \n", "55 COVID-19 patients from county 8 are treated at facility 13 \n", "57 COVID-19 patients from county 9 are treated at facility 13 \n", "300 is the total number of COVID-19 patients that are treated at facility 13. \n", "\n", "________________________________________________________________________________\n", "243 COVID-19 patients from county 9 are treated at facility 14 \n", "243 is the total number of COVID-19 patients that are treated at facility 14. \n", "\n", "________________________________________________________________________________\n", "140 COVID-19 patients from county 1 are treated at facility 15 \n", "140 is the total number of COVID-19 patients that are treated at facility 15. \n", "\n", "________________________________________________________________________________\n", "89 COVID-19 patients from county 2 are treated at facility 16 \n", "11 COVID-19 patients from county 3 are treated at facility 16 \n", "100 is the total number of COVID-19 patients that are treated at facility 16. \n", "\n", "________________________________________________________________________________\n", "127 COVID-19 patients from county 3 are treated at facility 17 \n", "127 is the total number of COVID-19 patients that are treated at facility 17. \n", "\n", "________________________________________________________________________________\n", "100 COVID-19 patients from county 4 are treated at facility 18 \n", "100 is the total number of COVID-19 patients that are treated at facility 18. \n", "\n", "________________________________________________________________________________\n", "100 COVID-19 patients from county 5 are treated at facility 19 \n", "100 is the total number of COVID-19 patients that are treated at facility 19. \n", "\n", "________________________________________________________________________________\n", "51 COVID-19 patients from county 5 are treated at facility 20 \n", "49 COVID-19 patients from county 6 are treated at facility 20 \n", "100 is the total number of COVID-19 patients that are treated at facility 20. \n", "\n", "________________________________________________________________________________\n", "26 COVID-19 patients from county 4 are treated at facility 21 \n", "74 COVID-19 patients from county 8 are treated at facility 21 \n", "100 is the total number of COVID-19 patients that are treated at facility 21. \n", "\n", "________________________________________________________________________________\n", "100 COVID-19 patients from county 8 are treated at facility 22 \n", "100 is the total number of COVID-19 patients that are treated at facility 22. \n", "\n", "________________________________________________________________________________\n", "48 COVID-19 patients from county 6 are treated at facility 23 \n", "52 COVID-19 patients from county 8 are treated at facility 23 \n", "100 is the total number of COVID-19 patients that are treated at facility 23. \n", "\n", "________________________________________________________________________________\n", "\n", "_____________Test demand = supply______________________\n", "Total demand is: 4,247 patients\n", "Total demand satisfied is: 4,247 beds\n" ] } ], "source": [ "# Increase in demand by 20%.\n", "\n", "for c in counties:\n", " forecast[c] = round(1.2*forecast[c])\n", " \n", "# find the optimal for scenario 1\n", "solve_covid19_facility(coordinates, forecast)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Analysis for Scenario 1\n", "\n", "The optimal total cost of building temporary COVID-19 healthcare facilities is $\\$4,500,000$, and nine temporary COVID-19 healthcare facilities are built. The total cost of allocating COVID-19 patients to healthcare facilities is $\\$25,520$, and \n", "40 and 27 beds need to be added at temporary healthcare facilities 15 and 17, respectively.\n", "\n", "Please note that in this scenario, the system is overloaded and all COVID-19 healthcare facilities are operating at full capacity. In addition, extra capacity needs to be added at some temporary healthcare facilities." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Conclusion\n", "\n", "In this example, we addressed the COVID-19 Healthcare Facility Capacity Optimization problem. We determined the optimal location and capacity of healthcare facilities in order to: \n", "* Satisfy demand from COVID-19 patients for treatment, \n", "* Minimize the cost of opening temporary facilities for healthcare providers, and \n", "* Predict the allocation of COVID-19 patients from a specific county to a specific healthcare facility.\n", "\n", "We explored two scenarios. In the base scenario, we have enough capacity and need to build three temporary healthcare facilities. Whereas in the alternative scenario (1) with an increase of 20% in the number of COVID-19 patients requiring hospitalization, we need to build nine temporary healthcare facilities and add extra capacity at two of them.\n", "\n", "Our COVID-19 Healthcare Facility Location Optimization model can be used by public health officials and healthcare providers to help make strategic decisions about when and where to increase healthcare facility capacity during the COVID-19 pandemic. Also, this strategic model can feed information to a COVID-19 load-balancing dispatching model that is capable of assigning (in real time) COVID-19 patients who require hospitalization to the \"right\" healthcare facilities.\n", "\n", "In addition, our model can feed into a tactical model that determines how capacity should be increased to accommodate any increase in demand. For example, the number medical personnel to be hired, trained, and re-skilled, the rotation of medical personnel, and the amount of equipment (e.g. ventilators, drugs, beds, etc.) needed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n", "[1] Katherine Klise and Michael Bynum. *Facility Location Optimization Model for COVID-19 Resources*. April 2020. Joint DOE Laboratory Pandemic Modeling and Analysis Capability. SAND2020-4693R." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copyright © 2020 Gurobi Optimization, LLC" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }