Software & Data

Well Economics in 5 Minutes: Free NPV, EUR, and Breakeven Calculators for E&P Engineers

Dr. Mehrdad Shirangi | | 24 min read | Published by Groundwork Analytics LLC

Editorial disclosure

This article reflects the independent analysis and professional opinion of the author, informed by published research and professional experience. No vendor reviewed or influenced this content prior to publication.

Every well decision is an economics decision. Whether you are screening drilling locations, evaluating an acquisition package, justifying a workover, or deciding whether a refrac makes sense at today's commodity prices, the question is always the same: does this well generate enough cash to justify the capital?

The math is not complicated. A reservoir engineer or production engineer who understands decline curves, cash flow projections, and time-value-of-money can evaluate a well's economics in a spreadsheet in under five minutes. The problem is that most engineers learn these concepts in a college course, apply them sporadically during their careers, and end up hunting for formulas every time a quick economic screen is needed.

This article is a permanent reference. It covers every calculation you need for single-well economics -- NPV, EUR, breakeven price, payout period, and IRR -- with both the mathematical formulas and working Python code. The examples use real-world cost assumptions from the Permian Basin, Eagle Ford, and Haynesville. Bookmark it.


Why Quick Economics Matter

Three situations demand fast well-level economics, and they come up constantly:

Screening drilling locations. A development team with 200 potential locations needs to rank them. The reservoir engineer provides a type curve (production forecast), and the economist provides cost and price assumptions. The output is a ranked list by NPV or IRR. This process happens quarterly at most operators, and the engineers who can run the numbers themselves -- without waiting for the economics team -- make better decisions faster.

Evaluating acquisitions. When an A&D package comes across the table, the first screen is always: what do these wells return at strip pricing? You do not need a full reservoir simulation to answer this. A decline curve fit to the production history, a forward price deck, and the standard economic model give you a defensible first-pass valuation in an afternoon.

Justifying workovers and refracs. A well making 30 BOPD that could make 120 BOPD after a refrac -- is it worth $1.5 million? The reservoir engineer who can calculate the incremental NPV of the refrac in a few minutes can make a compelling case to management without waiting for a formal AFE analysis.

In all three cases, the calculations are the same. What changes is the production forecast and the cost inputs.


EUR Estimation: Arps Decline Curves

Before you can calculate economics, you need a production forecast. In unconventional wells, that forecast almost always starts with Arps decline curve analysis.

The Arps Equations

J.J. Arps published his decline curve equations in 1945, and they remain the most widely used production forecasting method in the industry. The general Arps equation relates production rate to time:

General Arps decline:

q(t) = q_i / (1 + b * D_i * t)^(1/b)

Where:

  • q(t) = production rate at time t (BOPD or Mcf/d)
  • q_i = initial production rate
  • D_i = initial decline rate (1/month or 1/year)
  • b = decline exponent (dimensionless)
  • t = time (months or years, consistent with D_i)

The three special cases:

Exponential decline (b = 0):

q(t) = q_i * e^(-D_i * t)

EUR = q_i / D_i

Exponential decline assumes a constant fractional decline rate. It is the most conservative forecast and is appropriate for boundary-dominated flow in conventional reservoirs, or as a terminal decline model for unconventional wells.

Hyperbolic decline (0 < b < 1):

q(t) = q_i / (1 + b * D_i * t)^(1/b)

EUR = q_i / (D_i * (1 - b)) * [1 - (q_min/q_i)^(1 - b)]

Hyperbolic decline is the workhorse for unconventional wells during the transient flow period. The b factor controls how quickly the decline rate itself decreases over time. Higher b means a shallower decline.

Harmonic decline (b = 1):

q(t) = q_i / (1 + D_i * t)

EUR = q_i / D_i * ln(q_i / q_min)

Harmonic decline is a special case of hyperbolic decline where the decline rate is proportional to the production rate. It produces the most optimistic forecasts and is rarely used as a stand-alone model.

Fitting Decline Parameters from Production Data

In practice, you fit q_i, D_i, and b to actual production data using nonlinear regression. Here is a complete Python implementation using scipy.optimize.curve_fit:

import numpy as np
from scipy.optimize import curve_fit

def arps_hyperbolic(t, qi, di, b):
    """Arps hyperbolic decline: rate as a function of time."""
    return qi / (1 + b * di * t) ** (1 / b)

def arps_exponential(t, qi, di):
    """Arps exponential decline: rate as a function of time."""
    return qi * np.exp(-di * t)

def fit_decline_curve(time_months, production_bopd):
    """
    Fit Arps hyperbolic decline to production data.
    Returns (qi, di, b) with bounds to keep parameters physical.
    """
    # Initial guesses
    qi_guess = max(production_bopd)
    di_guess = 0.05  # 5% per month initial decline
    b_guess = 1.0

    try:
        popt, pcov = curve_fit(
            arps_hyperbolic,
            time_months,
            production_bopd,
            p0=[qi_guess, di_guess, b_guess],
            bounds=([0, 0.001, 0.01], [qi_guess * 2, 1.0, 2.0]),
            maxfev=10000
        )
        qi_fit, di_fit, b_fit = popt
        return qi_fit, di_fit, b_fit
    except RuntimeError:
        # Fall back to exponential if hyperbolic does not converge
        popt, pcov = curve_fit(
            arps_exponential,
            time_months,
            production_bopd,
            p0=[qi_guess, di_guess],
            bounds=([0, 0.001], [qi_guess * 2, 1.0])
        )
        qi_fit, di_fit = popt
        return qi_fit, di_fit, 0.0


def calculate_eur(qi, di, b, economic_limit_bopd=5.0, max_months=600):
    """
    Calculate EUR by numerically integrating the decline curve
    until the economic limit or max time is reached.
    """
    eur = 0.0
    for month in range(1, max_months + 1):
        if b == 0:
            rate = qi * np.exp(-di * month)
        else:
            rate = qi / (1 + b * di * month) ** (1 / b)
        if rate < economic_limit_bopd:
            break
        eur += rate * 30.44  # average days per month
    return eur


# --- Example usage ---
# Monthly production data (BOPD averages) for a Permian Wolfcamp well
time = np.array([1, 2, 3, 4, 5, 6, 9, 12, 18, 24, 36])
prod = np.array([1200, 980, 810, 700, 620, 560, 420, 340, 230, 175, 115])

qi, di, b = fit_decline_curve(time, prod)
eur_bbl = calculate_eur(qi, di, b)

print(f"Fitted parameters: qi={qi:.0f} BOPD, Di={di:.4f}/mo, b={b:.2f}")
print(f"EUR: {eur_bbl:,.0f} barrels")

Common Pitfalls in Decline Curve Analysis

b-factor greater than 1. In theory, Arps decline with b > 1 implies that cumulative production grows without bound -- an impossibility. In practice, b > 1 often results from fitting early transient data from unconventional wells before the decline has stabilized. If your fit returns b > 1.5, you are almost certainly overfitting early time data and your EUR will be unrealistically high.

No terminal decline rate. Hyperbolic decline with b > 0 never reaches a zero decline rate. If you extrapolate a hyperbolic curve with b = 1.2 for 50 years, you get absurd EURs. The standard fix is to switch from hyperbolic to exponential decline at a terminal decline rate (typically 5-8% per year, or D_min = 0.004-0.007 per month). This is called modified hyperbolic decline and is standard practice at most operators.

Fitting to noisy or short data. A well with 6 months of production history does not have enough data to reliably estimate three parameters. In these cases, constrain b to type-curve values from analogous wells (b = 1.0-1.4 for Wolfcamp oil, b = 0.8-1.2 for Eagle Ford oil, b = 1.5-2.0 for dry gas) and fit only q_i and D_i.

Ignoring operational downtime. Production data from state databases includes months where the well was shut in for workovers, offset frac hits, or facility issues. Fitting a decline curve to data that includes these zero or low months will bias your parameters. Clean your data before fitting -- remove months with zero production or rates more than 50% below the trend.


NPV Calculation

Net present value is the sum of all future cash flows, discounted back to the present. For a single well:

NPV = -CAPEX + SUM(t=1..T) [ (Revenue_t - Royalties_t - LOE_t - Taxes_t) / (1 + r)^t ]

Where:

  • CF_t = net cash flow in period t
  • r = discount rate per period
  • T = economic life of the well

Cash Flow Components

Revenue. Production rate (from your decline curve) multiplied by commodity price. For oil, this is BOPD x price/bbl x days. For gas, Mcf/d x price/Mcf x days. Many wells produce both oil and gas -- include both revenue streams. Use a fixed price for screening or a forward strip price deck for detailed analysis.

Royalties. Typically 12.5% to 25% of gross revenue, depending on the lease. State and federal royalties are deducted before the operator sees any revenue. A 20% royalty on a well producing $10M in revenue means $2M goes to mineral owners.

Lease operating expenses (LOE). Recurring costs to operate the well: chemical treatments, pumping costs, power, water disposal, workovers, field labor. LOE is typically expressed as $/BOE or $/month. Permian Basin LOE ranges from $5-12/BOE depending on the operator's scale and lift method. LOE generally increases over the well's life as water cut increases and artificial lift costs grow.

Capital expenditure (CAPEX). The upfront drilling and completion cost. For a new horizontal well in the Permian, this is $6.5-9.5 million depending on lateral length (1 mile vs 2+ miles) and completion design. CAPEX is a time-zero cash outflow (negative cash flow at t=0).

Severance and ad valorem taxes. State-level production taxes vary: Texas charges 4.6% of oil revenue and 7.5% of gas revenue. New Mexico charges 3.75% plus federal royalties on federal lands. Ad valorem (property) taxes on production typically add another 1-3%.

Discount Rate Selection

The discount rate reflects the time value of money and risk. Standard industry practice:

  • 10% annual discount rate is the most common assumption in upstream economics. It is used by the SEC for reserves reporting (PV-10) and serves as a reasonable baseline for comparing opportunities.
  • WACC-based discount rate is more rigorous. A company's weighted average cost of capital (typically 8-15% for E&P companies) represents the actual cost of the capital deployed. Use WACC for internal investment decisions.
  • Risk-adjusted rates of 12-20% are appropriate for exploration or high-uncertainty projects. Development wells in proven areas justify 8-12%.

For monthly cash flows, convert the annual discount rate:

r_monthly = (1 + r_annual)^(1/12) - 1

A 10% annual rate equals approximately 0.797% per month.

Python NPV Calculator

import numpy as np

def calculate_well_npv(
    qi_bopd,           # initial oil rate (BOPD)
    di_monthly,        # initial decline rate (1/month)
    b_factor,          # Arps b-factor
    oil_price,         # $/bbl (flat price assumption)
    capex,             # total D&C cost ($)
    royalty_rate=0.20,  # 20% royalty
    loe_per_boe=8.0,   # $/BOE operating cost
    severance_tax=0.046,  # Texas oil severance (4.6%)
    ad_valorem_tax=0.02,  # 2% ad valorem
    annual_discount_rate=0.10,
    economic_limit_bopd=5.0,
    max_months=480,
    gor=1.5,           # gas-oil ratio (Mcf/bbl)
    gas_price=3.0,     # $/Mcf
    ngl_yield=0.0,     # bbl NGL per Mcf gas
    ngl_price=25.0     # $/bbl NGL
):
    """
    Calculate NPV for a single oil/gas well using Arps decline.
    Returns NPV, monthly cash flows, and EUR.
    """
    monthly_discount = (1 + annual_discount_rate) ** (1/12) - 1
    days_per_month = 30.44

    cash_flows = [-capex]  # time zero: capex outflow
    cum_production = 0.0

    for month in range(1, max_months + 1):
        # Production rate from Arps decline
        if b_factor == 0:
            rate = qi_bopd * np.exp(-di_monthly * month)
        else:
            rate = qi_bopd / (1 + b_factor * di_monthly * month) ** (1 / b_factor)

        if rate < economic_limit_bopd:
            break

        # Monthly volumes
        oil_volume = rate * days_per_month  # barrels
        gas_volume = oil_volume * gor       # Mcf
        ngl_volume = gas_volume * ngl_yield # barrels

        # Gross revenue
        oil_revenue = oil_volume * oil_price
        gas_revenue = gas_volume * gas_price
        ngl_revenue = ngl_volume * ngl_price
        gross_revenue = oil_revenue + gas_revenue + ngl_revenue

        # Deductions
        royalties = gross_revenue * royalty_rate
        net_revenue = gross_revenue - royalties

        sev_tax = gross_revenue * severance_tax
        ad_val = gross_revenue * ad_valorem_tax

        boe_volume = oil_volume + gas_volume / 6.0 + ngl_volume
        operating_cost = boe_volume * loe_per_boe

        # Net cash flow
        ncf = net_revenue - sev_tax - ad_val - operating_cost
        cash_flows.append(ncf)

        cum_production += oil_volume

    # Calculate NPV
    npv = sum(
        cf / (1 + monthly_discount) ** t
        for t, cf in enumerate(cash_flows)
    )

    return npv, cash_flows, cum_production


# --- Permian Wolfcamp example ---
npv, cfs, eur = calculate_well_npv(
    qi_bopd=1100,
    di_monthly=0.065,
    b_factor=1.1,
    oil_price=51.0,
    capex=8_500_000,
    royalty_rate=0.20,
    loe_per_boe=8.0,
    gor=2.0,
    gas_price=3.00,
    ngl_yield=0.03,
    ngl_price=22.0
)

print(f"NPV (PV-10): ${npv:,.0f}")
print(f"EUR (oil): {eur:,.0f} barrels")
print(f"Economic life: {len(cfs) - 1} months")

Breakeven Price Calculation

The breakeven oil price is the commodity price at which the well's NPV equals zero. It is the minimum price at which the investment breaks even on a present-value basis.

Mathematical Formulation

Set NPV = 0 and solve for the oil price P:

Breakeven price equals total discounted costs divided by total discounted net production volumes. Where R is the royalty rate and tau terms are tax rates.

Python Breakeven Calculator

from scipy.optimize import brentq

def calculate_breakeven_price(
    qi_bopd, di_monthly, b_factor, capex,
    royalty_rate=0.20, loe_per_boe=8.0,
    severance_tax=0.046, ad_valorem_tax=0.02,
    annual_discount_rate=0.10,
    economic_limit_bopd=5.0, max_months=480,
    gor=1.5, gas_price=3.0
):
    """Find the oil price where NPV = 0 using root-finding."""

    def npv_at_price(price):
        npv, _, _ = calculate_well_npv(
            qi_bopd=qi_bopd,
            di_monthly=di_monthly,
            b_factor=b_factor,
            oil_price=price,
            capex=capex,
            royalty_rate=royalty_rate,
            loe_per_boe=loe_per_boe,
            severance_tax=severance_tax,
            ad_valorem_tax=ad_valorem_tax,
            annual_discount_rate=annual_discount_rate,
            economic_limit_bopd=economic_limit_bopd,
            max_months=max_months,
            gor=gor,
            gas_price=gas_price
        )
        return npv

    # Find the price where NPV = 0 (search between $10 and $200/bbl)
    breakeven = brentq(npv_at_price, 10.0, 200.0)
    return breakeven


# --- Example ---
be_price = calculate_breakeven_price(
    qi_bopd=1100, di_monthly=0.065, b_factor=1.1,
    capex=8_500_000, gor=2.0, gas_price=3.0
)
print(f"Breakeven oil price: ${be_price:.2f}/bbl")

Sensitivity Analysis

Breakeven price is sensitive to several inputs. Running sensitivity sweeps gives you a range rather than a point estimate:

def breakeven_sensitivity(base_params, vary_param, vary_range):
    """Sweep one parameter and compute breakeven at each value."""
    results = []
    for value in vary_range:
        params = base_params.copy()
        params[vary_param] = value
        be = calculate_breakeven_price(**params)
        results.append((value, be))
    return results

# Sensitivity to discount rate
base = dict(qi_bopd=1100, di_monthly=0.065, b_factor=1.1,
            capex=8_500_000, gor=2.0, gas_price=3.0)

for rate in [0.05, 0.08, 0.10, 0.12, 0.15]:
    base_copy = base.copy()
    base_copy['annual_discount_rate'] = rate
    be = calculate_breakeven_price(**base_copy)
    print(f"  Discount rate {rate:.0%}: breakeven = ${be:.2f}/bbl")

Typical sensitivities for a Permian Wolfcamp well:

  • LOE +$2/BOE raises breakeven by approximately $2-3/bbl
  • Discount rate from 8% to 12% raises breakeven by $3-5/bbl
  • Decline rate (Di) +10% relative raises breakeven by $2-4/bbl
  • Royalty rate from 20% to 25% raises breakeven by $4-6/bbl

Well Payout Calculator

Payout period is the time required for cumulative net cash flow to recover the initial capital investment. It is the single most intuitive economic metric -- when does this well pay for itself?

Simple Payback

Simple payback ignores the time value of money. It is the month at which cumulative undiscounted cash flow turns positive.

Discounted Payback

Discounted payback applies the discount rate, giving a more realistic (and longer) payout period.

Python Payout Calculator

def calculate_payout(cash_flows, annual_discount_rate=0.10):
    """
    Calculate simple and discounted payback periods.
    cash_flows[0] is the initial investment (negative).
    Returns (simple_payout_months, discounted_payout_months).
    """
    monthly_rate = (1 + annual_discount_rate) ** (1/12) - 1

    cum_simple = 0.0
    cum_discounted = 0.0
    simple_payout = None
    discounted_payout = None

    for t, cf in enumerate(cash_flows):
        cum_simple += cf
        cum_discounted += cf / (1 + monthly_rate) ** t

        if cum_simple >= 0 and simple_payout is None:
            simple_payout = t
        if cum_discounted >= 0 and discounted_payout is None:
            discounted_payout = t

    return simple_payout, discounted_payout


# Using the cash flows from the NPV calculation above
simple_po, disc_po = calculate_payout(cfs)
print(f"Simple payout: {simple_po} months ({simple_po/12:.1f} years)")
print(f"Discounted payout (PV-10): {disc_po} months ({disc_po/12:.1f} years)")

A Permian Wolfcamp well at $51 WTI with $8.5M capex typically pays out in 18-30 months on a simple basis, depending on IP rate and cost structure. Discounted payback adds 3-6 months. A well that does not pay out within 36 months at current strip pricing should be scrutinized.


Rate of Return (IRR)

The internal rate of return is the discount rate at which NPV equals zero. It is the effective annualized return on the capital invested in the well.

Python IRR Calculator

from scipy.optimize import brentq

def calculate_irr(cash_flows, max_rate=10.0):
    """
    Calculate the monthly IRR, then annualize.
    cash_flows[0] should be negative (investment).
    Returns annualized IRR as a decimal (0.25 = 25%).
    """
    def npv_at_rate(monthly_rate):
        return sum(
            cf / (1 + monthly_rate) ** t
            for t, cf in enumerate(cash_flows)
        )

    # Check if project is economic at all
    if sum(cash_flows) <= 0:
        return None  # never pays back even undiscounted

    try:
        monthly_irr = brentq(npv_at_rate, -0.01, max_rate)
        annual_irr = (1 + monthly_irr) ** 12 - 1
        return annual_irr
    except ValueError:
        return None  # no IRR found in range


# --- Example ---
irr = calculate_irr(cfs)
if irr is not None:
    print(f"IRR: {irr:.1%}")
else:
    print("Well is uneconomic -- no positive IRR")

When IRR Is Misleading

IRR has known limitations that every engineer should understand:

Short-lived, high-return projects. A well that costs $500K, returns $1M in 6 months, and dies is a fantastic IRR (over 100%). But it contributes $500K of value. A $9M well that returns $15M over 10 years has a much lower IRR but contributes $6M of value. NPV captures the absolute value created; IRR only captures the percentage return. For capital allocation decisions, NPV is the primary metric. Use IRR as a secondary screen.

Multiple IRR solutions. If the cash flow stream changes sign more than once (positive, then negative, then positive again -- common in wells requiring mid-life workovers), the IRR equation can have multiple solutions. In these cases, use modified IRR (MIRR) or rely on NPV.

Scale blindness. IRR does not distinguish between investing $100K and $100M. When ranking mutually exclusive projects of different scales, always use NPV.


Practical Examples

Example 1: Permian Wolfcamp Well at $51 WTI

A 2-mile lateral Wolfcamp A well in the Midland Basin with the following assumptions:

Parameter Value
IP-30 (avg first 30 days)1,100 BOPD
Decline: Di6.5%/month
Decline: b-factor1.1
GOR2.0 Mcf/bbl
NGL yield30 bbl/MMcf
D&C CAPEX$8.5 million
Oil price$51/bbl WTI
Gas price$3.00/Mcf
NGL price$22/bbl
Royalty20%
LOE$8/BOE
Severance tax4.6% (Texas)
npv, cfs, eur = calculate_well_npv(
    qi_bopd=1100, di_monthly=0.065, b_factor=1.1,
    oil_price=51.0, capex=8_500_000,
    royalty_rate=0.20, loe_per_boe=8.0,
    severance_tax=0.046, ad_valorem_tax=0.02,
    gor=2.0, gas_price=3.0, ngl_yield=0.03, ngl_price=22.0
)

irr = calculate_irr(cfs)
simple_po, disc_po = calculate_payout(cfs)
breakeven = calculate_breakeven_price(
    qi_bopd=1100, di_monthly=0.065, b_factor=1.1,
    capex=8_500_000, gor=2.0, gas_price=3.0
)

print(f"EUR (oil):       {eur:,.0f} bbl")
print(f"NPV (PV-10):     ${npv:,.0f}")
print(f"IRR:             {irr:.1%}")
print(f"Simple payout:   {simple_po} months")
print(f"Breakeven price: ${breakeven:.2f}/bbl")

Expected results: At $51 WTI, a strong Wolfcamp well generates a PV-10 of roughly $2-5M, an IRR of 25-45%, and breaks even at approximately $35-42/bbl. The wide range depends heavily on the type curve -- first-quartile wells in the core Midland Basin have significantly better economics than average wells in the periphery.

Example 2: Eagle Ford Refrac Economics

A 2015-vintage Eagle Ford well producing 40 BOPD with significant remaining reserves that could be unlocked by refracturing. The refrac is expected to restore production to 300 BOPD with a new decline profile.

Parameter Value
Pre-refrac rate40 BOPD
Post-refrac IP300 BOPD
Incremental IP260 BOPD
Decline: Di (post-refrac)7.0%/month
Decline: b-factor1.0
GOR1.0 Mcf/bbl
Refrac CAPEX$3.5 million
Oil price$51/bbl
Royalty22%
LOE$10/BOE (higher, older well)

For a refrac, you evaluate only the incremental production and the refrac cost -- the base decline would have happened anyway:

# Incremental production from refrac
npv_refrac, cfs_refrac, eur_incr = calculate_well_npv(
    qi_bopd=260,       # incremental rate
    di_monthly=0.070,
    b_factor=1.0,
    oil_price=51.0,
    capex=3_500_000,    # refrac cost only
    royalty_rate=0.22,
    loe_per_boe=10.0,
    severance_tax=0.046,
    gor=1.0,
    gas_price=3.0
)

irr_refrac = calculate_irr(cfs_refrac)
simple_po_rf, disc_po_rf = calculate_payout(cfs_refrac)

print(f"Incremental EUR:   {eur_incr:,.0f} bbl")
print(f"Refrac NPV (PV-10): ${npv_refrac:,.0f}")
print(f"Refrac IRR:        {irr_refrac:.1%}")
print(f"Refrac payout:     {simple_po_rf} months")

Expected results: Eagle Ford refracs at $51 WTI typically show NPVs of $1-3M on the incremental production, IRRs of 30-60%, and payouts of 12-20 months. Refracs are generally more capital-efficient than new drills (lower capex, decent returns), which is why operators like EOG, Devon, and Marathon have active refrac programs.

Example 3: Haynesville Gas Well at $3/MMBtu

A Haynesville Shale horizontal gas well with high initial rates and aggressive decline:

Parameter Value
IP-3025 MMcf/d (25,000 Mcf/d)
Decline: Di5.5%/month
Decline: b-factor1.3
Condensate yield5 bbl/MMcf
D&C CAPEX$12.0 million
Gas price$3.00/MMBtu
Condensate price$48/bbl
Royalty22%
LOE$0.40/Mcfe
Severance tax3.3% (Louisiana)

For gas wells, restructure the economics with gas as the primary revenue stream:

def calculate_gas_well_npv(
    qi_mcfd, di_monthly, b_factor, gas_price, capex,
    royalty_rate=0.22, loe_per_mcfe=0.40,
    severance_tax=0.033, ad_valorem_tax=0.015,
    annual_discount_rate=0.10,
    economic_limit_mcfd=100,
    condensate_yield=0.005,  # bbl per Mcf
    condensate_price=48.0,
    max_months=480
):
    """NPV for a gas well (Mcf/d primary, condensate secondary)."""
    monthly_rate = (1 + annual_discount_rate) ** (1/12) - 1
    days = 30.44

    cash_flows = [-capex]
    cum_gas = 0.0

    for month in range(1, max_months + 1):
        rate = qi_mcfd / (1 + b_factor * di_monthly * month) ** (1 / b_factor)
        if rate < economic_limit_mcfd:
            break

        gas_vol = rate * days           # Mcf
        cond_vol = gas_vol * condensate_yield  # bbl

        gross_rev = gas_vol * gas_price + cond_vol * condensate_price
        royalties = gross_rev * royalty_rate
        sev_tax = gross_rev * severance_tax
        ad_val = gross_rev * ad_valorem_tax
        loe = (gas_vol + cond_vol * 6) * loe_per_mcfe  # convert to Mcfe

        ncf = gross_rev - royalties - sev_tax - ad_val - loe
        cash_flows.append(ncf)
        cum_gas += gas_vol

    npv = sum(cf / (1 + monthly_rate) ** t for t, cf in enumerate(cash_flows))
    return npv, cash_flows, cum_gas


npv_hay, cfs_hay, eur_gas = calculate_gas_well_npv(
    qi_mcfd=25000, di_monthly=0.055, b_factor=1.3,
    gas_price=3.0, capex=12_000_000,
    condensate_yield=0.005, condensate_price=48.0
)

irr_hay = calculate_irr(cfs_hay)
simple_hay, disc_hay = calculate_payout(cfs_hay)

print(f"EUR (gas):       {eur_gas/1000:,.0f} MMcf")
print(f"NPV (PV-10):     ${npv_hay:,.0f}")
print(f"IRR:             {irr_hay:.1%}")
print(f"Simple payout:   {simple_hay} months")

Expected results: Haynesville economics at $3/MMBtu are marginal. Strong wells (25+ MMcf/d IP) can generate PV-10s of $2-6M and IRRs of 15-30%, but average wells struggle. The breakeven gas price for Haynesville is approximately $2.50-3.50/MMBtu depending on the operator's cost structure. The massive EURs (20-30 Bcf per well) are offset by high upfront capex and aggressive decline rates. Haynesville economics improve dramatically at $4+/MMBtu, which is why operators like Comstock and Expand Energy modulate activity based on the gas strip.


How AI Improves Well Economics

Traditional well economics relies on deterministic inputs: one type curve, one price assumption, one cost estimate. The output is a single NPV number that gives no indication of uncertainty. This is the fundamental weakness of standard decline curve economics -- it pretends that we know the future.

AI and machine learning improve well economics in three ways:

Better Decline Predictions

Physics-informed machine learning models that incorporate completion parameters (proppant loading, fluid volume, cluster spacing), geological features (porosity, TOC, formation thickness), and offset well performance produce more accurate production forecasts than Arps decline alone. A model that predicts the production trajectory within +/- 15% (vs +/- 40% for a type curve) narrows the range of economic outcomes significantly.

Recent work from operators like Chevron, Devon, and Pioneer (now ExxonMobil) has shown that ML-based production forecasting reduces EUR estimation error by 20-35% compared to traditional decline curve analysis, particularly in the first 12 months when the Arps fit is most uncertain.

Uncertainty Quantification

Instead of a single NPV, probabilistic models produce a distribution: P10 NPV, P50 NPV, P90 NPV. This is essential for portfolio-level decisions. A well with a P50 NPV of $3M and a P10 of -$2M is a fundamentally different investment than a well with a P50 of $3M and a P10 of $1M -- even though the expected values are identical. Monte Carlo simulation over decline parameters, price scenarios, and cost ranges gives decision-makers the full picture.

Automated Screening at Scale

An operator with 5,000 potential drilling locations cannot manually evaluate the economics of each one under multiple price scenarios. AI-powered screening tools can fit decline curves to analogous wells, apply location-specific cost assumptions, and generate ranked economics for the entire inventory in minutes. This allows development planners to run scenarios that would take weeks by hand: what happens to the inventory at $45 WTI? At $65? If LOE increases 20%? If we high-grade to only Tier 1 locations?


Programmatic Access with petro-mcp

If you work with production data programmatically -- whether building dashboards, running batch economics, or integrating with data pipelines -- petro-mcp provides a Model Context Protocol server for petroleum engineering calculations.

petro-mcp includes tools for:

  • Decline curve fitting -- Arps parameter estimation from production data
  • EUR calculation -- Modified hyperbolic with terminal decline
  • NPV and economics -- Full single-well economic model
  • Material balance -- Reservoir pressure and recovery calculations

The MCP protocol means these tools are callable from any AI agent or application that supports MCP -- including Claude, Cursor, and custom applications. Instead of rewriting the economics calculations every time, connect to the server and call the tools directly.

For engineers building internal tools, petro-mcp eliminates the need to maintain your own calculation library. For teams exploring agentic AI workflows, it provides the petroleum engineering calculation layer that general-purpose AI models lack.

Check out the project at github.com/petropt/petro-mcp, and explore AI-powered petroleum engineering tools at jobs.petropt.ai.


Summary

Well economics is not complicated, but getting it right requires discipline about inputs and assumptions. Here is the calculation checklist:

  1. 1.Fit a decline curve to production data (or use a type curve). Watch out for b > 1 and always apply a terminal decline rate.
  2. 2.Project monthly cash flows: revenue minus royalties, LOE, severance taxes, and ad valorem taxes.
  3. 3.Calculate NPV at 10% as the primary metric. This is the absolute value created by the investment.
  4. 4.Find the breakeven price by solving NPV = 0. This tells you how much commodity price protection you have.
  5. 5.Calculate payout period (both simple and discounted). If payout exceeds 36 months, scrutinize the project.
  6. 6.Calculate IRR as a secondary metric. Use it for comparison, not for ranking projects of different scale.
  7. 7.Run sensitivities on price, decline rate, LOE, and discount rate. A project that only works in one scenario is a bad bet.

The Python code in this article is a complete, working well economics toolkit. Copy it, modify it for your cost assumptions, and use it for screening. For production-grade calculations, programmatic access, and AI integration, explore petro-mcp.


Related Articles

Ready to Get Started?

Let's Build Something Together

Whether you're exploring AI for the first time or scaling an existing initiative, our team of petroleum engineers and data scientists can help.

Get in Touch →