Exercise 3.4
JSON Well Completion Report
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:
net_pay_ft(zones): total perforated thickness (sum ofbottom_ft − top_ft).total_perforations(zones): total shots fired:thickness_ft × shots_per_ft, summed.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.
flow_contribution(zones): a dict mapping eachformationto 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.
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 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.