Exerciseschevron_rightChapter 3chevron_right3.4
fitness_center

Exercise 3.4

JSON Well Completion Report

Level 2
Chapter 3: Data Structures
descriptionProblem

A multi-zone completion is described by a small JSON document: one record per perforated interval. Completion data arrives as JSON constantly (from the perforating contractor, the completion-design software, the well file), so reading it back into Python and summarising it is an everyday task.

The starter parses this completion for OD-003 into completion:

{
  "well": "OD-003",
  "field": "OML 58",
  "zones": [
    {"formation": "E2.0 Sand", "top_ft": 9650,  "bottom_ft": 9710,  "shots_per_ft": 6,  "perm_md": 250, "skin": 2.5},
    {"formation": "E3.0 Sand", "top_ft": 9820,  "bottom_ft": 9905,  "shots_per_ft": 12, "perm_md": 480, "skin": 1.0},
    {"formation": "E5.0 Sand", "top_ft": 10120, "bottom_ft": 10155, "shots_per_ft": 6,  "perm_md": 120, "skin": 4.0}
  ]
}

Write four functions that operate on the zones list:

  1. net_pay_ft(zones): total perforated thickness (sum of bottom_ft − top_ft).
  2. total_perforations(zones): total shots fired: thickness_ft × shots_per_ft, summed.
  3. zone_flow_index(zone): a zone's relative flow capacity. A perforated

zone flows in proportion to its permeability-thickness and inversely with its skin (near-wellbore damage). Use perm_md × net_thickness_ft / (LN_RE_RW + skin), where LN_RE_RW = 7.0 is a typical drainage term, held constant.

  1. flow_contribution(zones): a dict mapping each formation to its

percentage of the total flow index (the percentages sum to 100).

This tells you which zone is actually carrying the well: a thick, clean, high-perm zone can dominate flow even when the others add net pay.

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 json

COMPLETION_JSON = """
{
  "well": "OD-003",
  "field": "OML 58",
  "zones": [
    {"formation": "E2.0 Sand", "top_ft": 9650,  "bottom_ft": 9710,  "shots_per_ft": 6,  "perm_md": 250, "skin": 2.5},
    {"formation": "E3.0 Sand", "top_ft": 9820,  "bottom_ft": 9905,  "shots_per_ft": 12, "perm_md": 480, "skin": 1.0},
    {"formation": "E5.0 Sand", "top_ft": 10120, "bottom_ft": 10155, "shots_per_ft": 6,  "perm_md": 120, "skin": 4.0}
  ]
}
"""

completion = json.loads(COMPLETION_JSON)

LN_RE_RW = 7.0


def net_pay_ft(zones):
    return sum(z["bottom_ft"] - z["top_ft"] for z in zones)


def total_perforations(zones):
    return sum((z["bottom_ft"] - z["top_ft"]) * z["shots_per_ft"] for z in zones)


def zone_flow_index(zone):
    thickness_ft = zone["bottom_ft"] - zone["top_ft"]
    return zone["perm_md"] * thickness_ft / (LN_RE_RW + zone["skin"])


def flow_contribution(zones):
    total = sum(zone_flow_index(z) for z in zones)
    return {z["formation"]: 100.0 * zone_flow_index(z) / total for z in zones}


# A formatted completion summary - the kind you'd paste into a well file.
print(f"Completion summary - {completion['well']} ({completion['field']})")
print(f"  Net pay:      {net_pay_ft(completion['zones']):>6.0f} ft")
print(f"  Perforations: {total_perforations(completion['zones']):>6.0f} shots")
for formation, pct in flow_contribution(completion["zones"]).items():
    print(f"  {formation:<12} {pct:5.1f}% of flow")

lockCopying code is a Full Access feature.