Exerciseschevron_rightChapter 8chevron_right8.5
fitness_center

Exercise 8.5

Gas Volume & Expansion

Level 3
Chapter 8: PVT Correlations
descriptionProblem

A dry-gas pool on OML 58 holds 50 Bscf (50e9 standard cubic feet) of gas at initial conditions of Pi = 4500 psia and T = 220 °F, with a gas specific gravity of gamma_g = 0.72. Before you size the gathering line and book the reserve, you need the reservoir volume that gas actually occupies, and how much it swells as the field is drawn down.

Standard cubic feet are measured at surface conditions; in the reservoir each SCF takes up far less room because it is compressed. The bridge is the gas formation volume factor Bg, which depends on the deviation factor Z:

> Bg = 0.02829 Z (T_F + 460) / P (reservoir cubic feet per SCF, T in °R)

The z_factor(gamma_g, P_psia, T_F) correlation (Dranchuk–Abou-Kassem, with the Standing pseudocritical correlations) is provided: call it, don't re-derive it.

Write three functions:

  • bg_rcf_scf(z_factor_val, T_F, P): apply the Bg formula above. It takes

an already-computed Z, the temperature in °F, and pressure in psia.

  • reservoir_volume_rcf(gas_scf, bg): gas_scf * bg, the reservoir cubic

feet occupied by gas_scf standard cubic feet at that Bg.

  • analyze(gas_scf, gamma_g, T_F, P): tie it together. Compute Z from

z_factor, then Bg, then reservoir volume, and return a dict {"z": ..., "bg": ..., "res_volume_rcf": ...}.

Then evaluate the pool at two pressures (same temperature, same gamma_g):

  • initial = analyze(50e9, 0.72, 220, 4500)
  • depleted = analyze(50e9, 0.72, 220, 2000)

As pressure falls the gas expands: Bg grows, so the same standard volume fills more reservoir space. Store the expansion as expansion_ratio = depleted["bg"] / initial["bg"]; it should come out greater than 1.

lightbulbHints (0/3)

Stuck? Reveal hints one at a time — they progress from nudge to near-solution.

codeYour solution
main.py
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

# ── OML 58 dry-gas pool ──────────────────────────────────────────────────
GAS_SCF = 50e9        # 50 Bscf in place
GAMMA_G = 0.72        # gas specific gravity
T_F = 220.0           # reservoir temperature, deg F
PI_PSIA = 4500.0      # initial pressure, psia
P_DEPLETED_PSIA = 2000.0  # drawn-down pressure, psia


# ── Provided correlations - call them, don't re-derive ───────────────────
def pseudocritical_properties(gamma_g):
    Ppc = 756.8 - 131.0 * gamma_g - 3.6 * gamma_g ** 2
    Tpc = 169.2 + 349.5 * gamma_g - 74.0 * gamma_g ** 2
    return Ppc, Tpc


def z_factor_DAK(Ppr, Tpr, tol=1e-8, max_iter=100):
    A1, A2, A3, A4 = 0.3265, -1.0700, -0.5339, 0.01569
    A5, A6, A7, A8 = -0.05165, 0.5475, -0.7361, 0.1844
    A9, A10, A11 = 0.1056, 0.6134, 0.7210
    Z = 1.0
    for _ in range(max_iter):
        rho_r = 0.27 * Ppr / (Z * Tpr)
        c1 = A1 + A2 / Tpr + A3 / Tpr ** 3 + A4 / Tpr ** 4 + A5 / Tpr ** 5
        c2 = A6 + A7 / Tpr + A8 / Tpr ** 2
        c3 = A9 * (A7 / Tpr + A8 / Tpr ** 2)
        c4 = A10 * (1 + A11 * rho_r ** 2) * (rho_r ** 2 / Tpr ** 3) * np.exp(-A11 * rho_r ** 2)
        f = Z - 1 - c1 * rho_r - c2 * rho_r ** 2 + c3 * rho_r ** 5 - c4
        d_rho_dZ = -rho_r / Z
        df = (1 - c1 * d_rho_dZ - 2 * c2 * rho_r * d_rho_dZ + 5 * c3 * rho_r ** 4 * d_rho_dZ
              - A10 / Tpr ** 3 * d_rho_dZ * rho_r
              * (2 * rho_r * (1 + A11 * rho_r ** 2) - 2 * A11 * rho_r ** 3) * np.exp(-A11 * rho_r ** 2))
        Z_new = Z - f / df
        if abs(Z_new - Z) < tol:
            return Z_new
        Z = Z_new
    return Z


def z_factor(gamma_g, P_psia, T_F):
    Ppc, Tpc = pseudocritical_properties(gamma_g)
    return z_factor_DAK(P_psia / Ppc, (T_F + 460.0) / Tpc)


# ── Your work ────────────────────────────────────────────────────────────
def bg_rcf_scf(z_factor_val, T_F, P):
    """Gas formation volume factor (RCF/SCF). Bg = 0.02829 * Z * (T_F+460) / P."""
    return 0.02829 * z_factor_val * (T_F + 460.0) / P


def reservoir_volume_rcf(gas_scf, bg):
    """Reservoir cubic feet occupied by gas_scf standard cubic feet."""
    return gas_scf * bg


def analyze(gas_scf, gamma_g, T_F, P):
    """Return {"z", "bg", "res_volume_rcf"} for the gas pool at pressure P."""
    z = z_factor(gamma_g, P, T_F)
    bg = bg_rcf_scf(z, T_F, P)
    res = reservoir_volume_rcf(gas_scf, bg)
    return {"z": z, "bg": bg, "res_volume_rcf": res}


initial = analyze(GAS_SCF, GAMMA_G, T_F, PI_PSIA)
depleted = analyze(GAS_SCF, GAMMA_G, T_F, P_DEPLETED_PSIA)
expansion_ratio = depleted["bg"] / initial["bg"]

print("initial  :", initial)
print("depleted :", depleted)
print("expansion ratio:", expansion_ratio)

lockCopying code is a Full Access feature.