Exercise 12.3
Composite IPR Construction - Bubble-Point Transition Rate
A reservoir has Pe = 5,000 psi, Pb = 3,600 psi, and J = 10 STB/day/psi. Construct the composite IPR (linear above Pb, Vogel below). At what rate does the flow regime transition from single-phase to two-phase?
---
This OML-127 well is undersaturated: the reservoir pressure Pe = 5000 psi sits comfortably above the bubble point Pb = 3600 psi, with a productivity index J = 10 STB/day/psi. While the flowing bottomhole pressure stays above Pb, the inflow is plain linear Darcy flow: q = J*(Pe - Pwf). The moment Pwf dips below Pb, gas comes out of solution near the wellbore and the inflow bends over into Vogel's two-phase curve. The composite IPR stitches the two together at the bubble point.
The verified composite_ipr(Pe, Pb, J, Pwf_array) is embedded for you. Do not modify it or re-derive the physics. It is linear above Pb, Vogel below, with the bubble-point rate qb = J*(Pe - Pb) and the absolute open flow qo_max = qb + J*Pb/1.8. The constants (verbatim from Exercise 12.3) are PE = 5000.0, PB = 3600.0, J = 10.0.
Your tasks:
- Write
transition_rate(Pe, Pb, J), the oil rate at the bubble point, i.e.
the rate at which the flow regime switches from single-phase to two-phase. This is simply qb = J * (Pe - Pb). Return it as a float.
- Build the full inflow curve and read off the anchor scalars:
q_transition = transition_rate(PE, PB, J)PWF_CURVE = np.linspace(0, PE, 300)and
q_curve = composite_ipr(PE, PB, J, PWF_CURVE) (length 300).
qo_max = float(q_transition + J*PB/1.8), the composite AOF (absolute
open flow, the rate at Pwf = 0).
q_at_zero = float(composite_ipr(PE, PB, J, [0.0])[0]), the rate at
Pwf = 0; it must equal qo_max.
q_above_pb = float(composite_ipr(PE, PB, J, [4000.0])[0]), a point in
the linear region (4000 psi is above Pb), so this is just J*(Pe - 4000).
> Think about it: at Pwf = Pb the two branches must meet. The linear > rate J*(Pe - Pb) and the start of the Vogel branch are the same number, so > the curve is continuous (no jump). Below Pb, why does the composite rate fall > short of the naive linear extrapolation J*(Pe - Pwf)? That gap is the Vogel > gas-interference penalty.
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
# ── Verified composite IPR from the chapter (do not edit) ────────────────
def composite_ipr(Pe, Pb, J, Pwf_array):
"""
Composite IPR: linear above bubble point, Vogel below.
This is the standard approach when reservoir pressure
exceeds the bubble point but flowing pressure may drop below it.
"""
Pwf = np.asarray(Pwf_array)
q = np.zeros_like(Pwf, dtype=float)
# Rate at the bubble point (transition point)
qb = J * (Pe - Pb)
# Maximum rate using Vogel below bubble point
qo_max = qb + J * Pb / 1.8
for i, pw in enumerate(Pwf):
if pw >= Pb:
# Linear region (undersaturated)
q[i] = J * (Pe - pw)
else:
# Vogel region (two-phase near wellbore)
q[i] = qb + (qo_max - qb) * (1 - 0.2*(pw/Pb) - 0.8*(pw/Pb)**2)
return q
# ── OML-127 well constants (verbatim from Exercise 12.3, do not edit) ─────
PE = 5000.0 # reservoir pressure, psi
PB = 3600.0 # bubble point, psi
J = 10.0 # productivity index, STB/day/psi
def transition_rate(Pe, Pb, J):
"""Oil rate at the bubble point where flow goes single-phase -> two-phase.
This is the bubble-point rate qb = J * (Pe - Pb): everything above Pb is
linear Darcy flow, everything below it bends into Vogel's two-phase curve.
Return it as a float.
"""
qb = J * (Pe - Pb)
return float(qb)
q_transition = transition_rate(PE, PB, J)
PWF_CURVE = np.linspace(0, PE, 300)
q_curve = composite_ipr(PE, PB, J, PWF_CURVE)
qo_max = float(q_transition + J * PB / 1.8)
q_at_zero = float(composite_ipr(PE, PB, J, [0.0])[0])
q_above_pb = float(composite_ipr(PE, PB, J, [4000.0])[0])
print("transition rate qb (STB/day):", q_transition)
print("absolute open flow qo_max (STB/day):", qo_max)
print("rate at Pwf=0 (STB/day):", q_at_zero)
print("rate at Pwf=4000 psi, linear region (STB/day):", q_above_pb)
lockCopying code is a Full Access feature.