Exercise 6.1
LAS File Inspection
Before you analyse a well log, you inspect it. The header tells you the well, the field, the depth range, and which curves you actually have, all before you trust a single number. The starter holds a real-shape LAS file for OD-007 (a shale–sand–shale sequence) as LAS_TEXT. Note one resistivity reading is the LAS null value -999.25, and lasio turns that into NaN when it builds the DataFrame, which is exactly what you want.
Write three functions (read the file with lasio.read(io.StringIO(LAS_TEXT))):
header_info(las): a dict withwell,field,start_ft,stop_ft,
and step_ft pulled from the well section (las.well.WELL.value, las.well.FLD.value, STRT, STOP, STEP).
curve_mnemonics(las): the list of curve mnemonics
([c.mnemonic for c in las.curves]), including the depth curve.
curve_stats(las): fromlas.df(), return
{mnemonic: {"min": ..., "max": ..., "mean": ...}} for each data curve. Because lasio already mapped -999.25 → NaN, the stats skip the null automatically (that's why you never compute statistics on raw LAS data without null handling first).
The point: the header and a stats pass are the 30-second sanity check every petrophysicist runs before doing any real work on a log.
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 lasio
import io
import pandas as pd # las.df() builds a pandas DataFrame under the hood
LAS_TEXT = """~VERSION INFORMATION
VERS. 2.0 : CWLS LOG ASCII STANDARD - VERSION 2.0
WRAP. NO : ONE LINE PER DEPTH STEP
~WELL INFORMATION
WELL. OD-007 : Well Name
FLD. OML 58 : Field Name
COMP. NATIONAL PETRO : Company
SRVC. SCHLUMBERGER : Service Company
DATE. 10-FEB-2025 : Log Date
STRT. 9000.000 : START DEPTH (FT)
STOP. 9005.500 : STOP DEPTH (FT)
STEP. 0.500 : STEP (FT)
NULL. -999.2500 : NULL VALUE
~CURVE INFORMATION
DEPT.FT : Depth
GR .GAPI : Gamma Ray
RT .OHMM : Deep Resistivity
RHOB.G/CC : Bulk Density
NPHI.V/V : Neutron Porosity
~A DEPT GR RT RHOB NPHI
9000.000 92.0 2.1 2.49 0.31
9000.500 95.5 1.9 2.51 0.33
9001.000 88.0 2.4 2.47 0.29
9001.500 44.0 18.5 2.32 0.16
9002.000 39.5 25.0 2.29 0.14
9002.500 41.0 -999.25 2.30 0.15
9003.000 38.0 31.0 2.28 0.13
9003.500 47.0 15.0 2.34 0.17
9004.000 90.0 2.2 2.50 0.32
9004.500 96.0 1.8 2.52 0.34
9005.000 93.0 2.0 2.49 0.31
9005.500 91.0 2.3 2.48 0.30
"""
def header_info(las):
return {
"well": las.well.WELL.value,
"field": las.well.FLD.value,
"start_ft": float(las.well.STRT.value),
"stop_ft": float(las.well.STOP.value),
"step_ft": float(las.well.STEP.value),
}
def curve_mnemonics(las):
return [c.mnemonic for c in las.curves]
def curve_stats(las):
df = las.df()
return {
col: {"min": float(df[col].min()), "max": float(df[col].max()), "mean": float(df[col].mean())}
for col in df.columns
}
las = lasio.read(io.StringIO(LAS_TEXT))
info = header_info(las)
print(f"{info['well']} ({info['field']}): {info['start_ft']:.0f}-{info['stop_ft']:.0f} ft, step {info['step_ft']} ft")
print("Curves:", curve_mnemonics(las))
for mnem, s in curve_stats(las).items():
print(f" {mnem:5s} min={s['min']:.2f} max={s['max']:.2f} mean={s['mean']:.2f}")
lockCopying code is a Full Access feature.