Exercise 13.1
Basic Rate Allocation - Pipeline-Constrained Oil & Profit LP
Three wells with maximum rates of 1,000, 800, and 1,500 STB/day share a pipeline with 2,500 STB/day capacity. Each well has operating costs of 14, and $8 per barrel respectively. Formulate and solve the allocation to maximize oil production, then separately to maximize profit.
---
Three wells on OML 58 feed one shared export pipeline. Each well has a maximum oil rate and a per-barrel operating cost, and the pipeline can only move 2500 STB/d total. You will solve the same allocation two different ways with scipy.optimize.linprog: once to maximize barrels, once to maximize dollars. And see why they disagree.
The three-well system constants are embedded for you (do not edit them):
MAX_OIL = np.array([1000.0, 800.0, 1500.0]) # STB/d per well
OP_COST = np.array([10.0, 14.0, 8.0]) # $/STB operating cost per well
PIPELINE_BPD = 2500.0 # shared pipeline capacity, STB/d
OIL_PRICE = 75.0 # $/bbl (house value, same as 13.9)Every barrel is bounded by 0 <= rate_i <= MAX_OIL[i], and the whole field is bounded by sum(rates) <= PIPELINE_BPD. Both functions build that same linear program; only the objective changes.
Your tasks:
- Write
allocate_max_oil(max_oil, pipeline):
- Maximize total oil subject to
sum(rates) <= pipelineand the per-well
bounds. Because linprog minimizes, use c = -np.ones(n).
- Build
A_ub = [[1, 1, ..., 1]],b_ub = [pipeline],
bounds = [(0, m) for m in max_oil], and call linprog(..., method='highs').
- Return the tuple
(rates, total_oil)whererates = result.xand
total_oil = float(result.x.sum()).
- Write
allocate_max_profit(max_oil, op_cost, price, pipeline):
- The per-barrel margin is
margin = price - op_cost. Maximize
sum(margin_i * rate_i), so c = -margin. Use the same A_ub, b_ub, and bounds as task 1.
- Return the tuple
(rates, total_profit)whererates = result.xand
total_profit = float(np.sum(margin * rates)).
- After defining both, assign the module-level output variables the tests read:
rates_oil, total_oil = allocate_max_oil(MAX_OIL, PIPELINE_BPD)
rates_profit, total_profit = allocate_max_profit(MAX_OIL, OP_COST, OIL_PRICE, PIPELINE_BPD)> Think about it: the max-oil solution just fills the pipeline to 2500 > STB/d. Any split that sums to 2500 is equally good, so the barrels are fixed > but the per-well rates are not unique. The max-profit solution is different: > with margins price - cost = [65, 61, 67], the cheapest-margin well (well 2, > the $14 one) is the first to drop to zero, and the pipeline fills with the two > high-margin wells. Why does optimizing dollars instead of barrels change which > wells you choke back?
Stuck? Reveal hints one at a time — they progress from nudge to near-solution.
visibilityReveal reference solutionexpand_more
Try solving it yourself first — the hints walk you through it. The solution below is one valid approach; yours may differ and still be correct.
import numpy as np
from scipy.optimize import linprog
# ── OML-58 three-well allocation system (do not edit) ────────────────────
# The LP pattern below mirrors the chapter's ch13-linprog cell: linprog
# minimizes, so the objective is negated, the pipeline cap is one A_ub row,
# and the per-well maxima are box bounds.
MAX_OIL = np.array([1000.0, 800.0, 1500.0]) # STB/d per well
OP_COST = np.array([10.0, 14.0, 8.0]) # $/STB operating cost per well
PIPELINE_BPD = 2500.0 # shared pipeline capacity, STB/d
OIL_PRICE = 75.0 # $/bbl (house value, same as 13.9)
def allocate_max_oil(max_oil, pipeline):
"""Maximize total oil through the pipeline.
Returns (rates, total_oil):
rates = per-well STB/d array (result.x) that maximizes total oil
subject to sum(rates) <= pipeline and 0 <= rate_i <= max_oil_i
total_oil = float(rates.sum())
"""
n = len(max_oil)
c = -np.ones(n) # minimize -> negate the oil objective
A_ub = [[1.0] * n] # sum(rates) ...
b_ub = [pipeline] # ... <= pipeline
bounds = [(0, m) for m in max_oil] # 0 <= rate_i <= max_oil_i
result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')
return result.x, float(result.x.sum())
def allocate_max_profit(max_oil, op_cost, price, pipeline):
"""Maximize total profit through the pipeline.
Returns (rates, total_profit):
rates = per-well STB/d array (result.x) that maximizes
sum((price - op_cost_i) * rate_i) under the same
pipeline + bound constraints
total_profit = float(sum(margin * rates))
"""
n = len(max_oil)
margin = price - op_cost # per-barrel profit margin
c = -margin # minimize -> negate the profit objective
A_ub = [[1.0] * n]
b_ub = [pipeline]
bounds = [(0, m) for m in max_oil]
result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')
rates = result.x
return rates, float(np.sum(margin * rates))
rates_oil, total_oil = allocate_max_oil(MAX_OIL, PIPELINE_BPD)
rates_profit, total_profit = allocate_max_profit(MAX_OIL, OP_COST, OIL_PRICE, PIPELINE_BPD)
print("max-oil: total_oil =", total_oil, " rates =", rates_oil)
print("max-profit: total_profit =", total_profit, " rates =", rates_profit)
lockCopying code is a Full Access feature.