Well Log Evaluation logo

Well Log Evaluation

Community
SteadfastAsArt
well-log-evaluation

Complete well log evaluation workflow from LAS/DLIS loading through QC, petrophysical analysis, lithology classification, and visualization. Use when performing formation evaluation from well log data.

Overview

PublisherSteadfastAsArt
Repositorygeoscience-skills
Skill namewell-log-evaluation
Stars
75
Forks
9
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by SteadfastAsArt on GitHub. Read the source before you install it.

Installation

Install the Well Log Evaluation AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/SteadfastAsArt/geoscience-skills/tree/main/workflows/well-log-evaluation
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/SteadfastAsArt/geoscience-skills.git /tmp/geoscience-skills
mkdir -p .claude/skills
cp -r /tmp/geoscience-skills/workflows/well-log-evaluation .claude/skills/well-log-evaluation
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Well Log Evaluation in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Well Log Evaluation on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Well Log Evaluation is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Well Log Evaluation Workflow

End-to-end pipeline for formation evaluation, from loading well log files through quality control, petrophysical analysis, lithology classification, and multi-dimensional visualization.

Skill Chain

text
lasio/dlisio     welly           petropy         striplog        pyvista
[File I/O]   --> [QC & Prep]  --> [Petrophysics] --> [Lithology] --> [3D Viz]
  |               |                |                 |               |
  LAS parsing     Despike          Vshale calc       Facies log      3D well
  DLIS frames     Normalize        Porosity          Intervals       Fence diagram
  Curve extract   Merge curves     Sw, Perm          Correlation     Property vol

Decision Points

QuestionIf YesIf No
LAS format (.las)?Use lasio for loadingCheck DLIS format
DLIS format (.dlis)?Use dlisio for loadingCheck file type
Multiple wells or curve QC needed?Use welly for managementUse lasio directly
Full formation evaluation (Sw, phi, Vsh)?Use petropyCompute manually with numpy
Need lithology column or stratigraphic log?Use striplogSkip to visualization
3D well trajectory visualization?Use pyvistaUse matplotlib for log plots

Step-by-Step Orchestration

Stage 1: Data Loading (lasio / dlisio)

The LAS example below assumes depth in metres, GR in API, bulk density in g/cm³, and resistivity in ohm-m. Inspect the headers and convert other units before continuing. The DLIS block is an alternative inspection entrypoint; select a frame, map mnemonics, and supply the same units before Stage 2.

python
import lasio
import numpy as np
import pandas as pd

# Load LAS file
las = lasio.read('well_A.las')
df = las.df().rename_axis('DEPT').reset_index()
null_val = float(las.well['NULL'].value)
df = df.replace(null_val, np.nan)
if las.curves[0].unit.strip().lower() not in {'m', 'metre', 'meter'}:
    raise ValueError('Convert the depth basis to metres before this example')
if (len(df) < 2 or not np.isfinite(df['DEPT']).all()
        or not np.all(np.diff(df['DEPT']) > 0)):
    raise ValueError('QC the depth basis: require finite, strictly increasing samples')

# Inspect available curves
print(las.curves.keys())  # ['DEPT', 'GR', 'RHOB', 'NPHI', 'RT', 'DT']
well_name = las.well['WELL'].value
python
import dlisio

# Load DLIS file (for modern well data)
with dlisio.dlis.load('well_B.dlis') as files:
    f = files[0]
    for frame in f.frames:
        print(frame.name, [ch.name for ch in frame.channels])
    # Extract channels to numpy arrays
    frame = f.frames[0]
    depth = frame.channels[0].curves()
    gr = frame.channels[1].curves()

Stage 2: QC and Preparation (welly)

python
from welly import Well

# Build from Stage 1's validated/converted dataframe so edits are retained.
w = Well.from_df(df.set_index('DEPT'),
                 units={'GR': 'API', 'RHOB': 'g/cm3', 'RT': 'ohm-m'})

required = ['GR', 'RHOB', 'RT']  # NPHI is optional for this density-only example.
missing = set(required) - set(w.data)
if missing:
    raise ValueError(f'Missing required curves: {sorted(missing)}')

# Review the despiking parameters against real beds; retain GR in API units.
# despike returns a new Curve, so explicitly use it for subsequent resampling.
w.data['GR'] = w.data['GR'].despike(window_length=33, z=2.0)

# Sample only the common measured depth range; do not extrapolate edge values.
step_m = 0.5
start = max(w.data[key].start for key in required)
stop = min(w.data[key].stop for key in required)
if not np.isfinite([start, stop]).all() or stop <= start:
    raise ValueError('Curves need an overlapping, increasing depth range')
basis = start + np.arange(int(np.floor((stop - start) / step_m)) + 1) * step_m
if len(basis) < 2:
    raise ValueError('Need at least two samples on the target depth basis')
df = w.df(keys=required, basis=basis).replace([np.inf, -np.inf], np.nan)
df = df.rename_axis('DEPT').reset_index()

# Keep missing rows so later classification cannot bridge unlogged intervals.
df['QC_VALID'] = (np.isfinite(df[required]).all(axis=1)
                  & (df['RHOB'] > 0) & (df['RT'] > 0))

The welly Curve guide describes despiking and resampling. These snippets are tested with welly 0.5.2 and pandas 2.3.3; welly 0.5.2 also requires setuptools<81 for pkg_resources.

Stage 3: Petrophysical Analysis

This runnable calculation uses the QC dataframe from Stage 2. The sand/shale GR endpoints, fluid density, Rw at formation temperature, and Archie parameters below are illustrative inputs requiring local calibration. Archie applies to clean formations; use an appropriate shale-aware model for shaly intervals. For a PetroPy multimineral model, first export the QC curves and configure formation tops, fluid properties, and model parameters; follow the PetroPy API.

python
valid = df['QC_VALID'].to_numpy(dtype=bool)
gr_sand, gr_shale = 20.0, 120.0  # API, calibrated endpoints (example values)
if not np.isfinite([gr_sand, gr_shale]).all() or gr_shale <= gr_sand:
    raise ValueError('GR endpoints must be finite with shale > sand')
vshale = np.where(valid, np.clip((df['GR'] - gr_sand) / (gr_shale - gr_sand), 0, 1), np.nan)

# 2. Porosity from density log
rho_matrix = 2.65   # g/cc (quartz)
rho_fluid = 1.0     # g/cc (freshwater)
phi_density = (rho_matrix - df['RHOB']) / (rho_matrix - rho_fluid)
phi_density = phi_density.where(valid & phi_density.between(0, 1))

# 3. Water saturation (Archie equation)
a, m, n = 1.0, 2.0, 2.0  # Archie parameters
Rw = 0.05                  # Formation water resistivity (ohm-m)
Rt = df['RT'].values       # True resistivity
phi = phi_density.values
Sw_raw = np.full(len(df), np.nan)
usable = valid & np.isfinite(phi) & (phi > 0)
Sw_raw[usable] = ((a * Rw) / (phi[usable]**m * Rt[usable]))**(1/n)
Sw = np.clip(Sw_raw, 0, 1)
df['VSH'], df['PHI_D'], df['SW'] = vshale, phi_density, Sw
df['SW_CLIPPED'] = Sw_raw > 1  # Retain a flag to review model/input mismatch.
df.to_csv('well_A_evaluated.csv', index=False)

Estimate permeability only with a calibrated model and its required inputs (for example, irreducible water saturation or NMR bound/free-fluid volumes). The Archie saturation above is not automatically irreducible saturation.

Stage 4: Lithology Classification (striplog)

python
from striplog import Striplog, Component, Interval

# Build lithology log from Vshale cutoffs
intervals = []
depth = df['DEPT'].values
for i in range(len(depth) - 1):
    if not np.isfinite(vshale[i:i+2]).all():
        continue  # Preserve gaps; do not invent a lithology across missing data.
    if vshale[i] < 0.3:
        lith = Component({'lithology': 'sandstone'})
    elif vshale[i] < 0.6:
        lith = Component({'lithology': 'siltstone'})
    else:
        lith = Component({'lithology': 'shale'})
    intervals.append(Interval(top=depth[i], base=depth[i+1], components=[lith]))

if not intervals:
    raise ValueError('No adjacent valid samples for lithology intervals')
strip = Striplog(intervals).merge_neighbours()

Optional display:

python
strip.plot(aspect=10)

Stage 5: Visualization (pyvista)

Use a surveyed trajectory with MD_M, X_M, Y_M, and TVDSS_M columns in trajectory.csv; MD must use the same datum as the logs. X/Y use a documented projected CRS in metres, and TVDSS is positive down from the stated vertical datum. Measured depth is not vertical depth in a deviated well.

python
import pyvista as pv

# Interpolate surveyed coordinates onto the evaluated log sample depths.
survey = pd.read_csv('trajectory.csv')
md = survey['MD_M'].to_numpy()
if (len(md) < 2 or not np.isfinite(survey[['MD_M', 'X_M', 'Y_M', 'TVDSS_M']]).all().all()
        or not np.all(np.diff(md) > 0)):
    raise ValueError('Survey coordinates must be finite with increasing MD')
depth = df['DEPT'].to_numpy()
if depth.min() < md[0] or depth.max() > md[-1]:
    raise ValueError('Survey must cover the log depth range')
trajectory = np.column_stack([
    np.interp(depth, md, survey['X_M']),
    np.interp(depth, md, survey['Y_M']),
    -np.interp(depth, md, survey['TVDSS_M']),
])
well_path = pv.lines_from_points(trajectory)  # Keep one point per log sample.
well_path['GR'] = df['GR'].values
well_path['Porosity'] = phi_density.values

Optional interactive display:

python
plotter = pv.Plotter()
plotter.add_mesh(well_path, scalars='Porosity', cmap='viridis',
                 line_width=5, render_lines_as_tubes=True)
plotter.show()

Common Pipelines

Standard Formation Evaluation

text
- [ ] Load LAS file with `lasio.read()`, replace null values with NaN
- [ ] Inspect GR, RHOB and RT for this example; add NPHI or DT for models that require them
- [ ] QC curves with welly: despike, check ranges, identify washouts (caliper)
- [ ] Calculate Vshale from GR (linear, Larionov, or Clavier method)
- [ ] Calculate porosity from density or neutron-density crossplot
- [ ] Calculate water saturation using Archie or dual-water model
- [ ] Estimate permeability from Timur-Coates or Wyllie-Rose
- [ ] Flag pay zones: phi > cutoff, Sw < cutoff, Vsh < cutoff
- [ ] Generate composite log plot (GR, resistivity, porosity, Sw, pay flag)
- [ ] Export results to LAS or CSV

Multi-Well Correlation

text
- [ ] Load multiple LAS files with lasio or welly batch loading
- [ ] Standardize curve mnemonics across wells (GR, GRGC, SGR -> GR)
- [ ] Normalize GR logs to common scale across wells
- [ ] Pick formation tops manually or from Vshale transitions
- [ ] Create striplog for each well with formation intervals
- [ ] Build correlation panel with matplotlib or pyvista
- [ ] Export formation tops to CSV

Quick Log QC

text
- [ ] Load LAS file with `lasio.read()`
- [ ] Check depth range, step, and null values
- [ ] Print curve statistics: min, max, mean, NaN count
- [ ] Flag out-of-range values (GR: 0-300, RHOB: 1.5-3.0, NPHI: -0.05-0.6)
- [ ] Check for constant or stuck readings
- [ ] Identify depth intervals with poor data (washout from caliper)
- [ ] Plot all curves for visual inspection

When to Use

Use the well log evaluation workflow when:

  • Performing formation evaluation from LAS or DLIS well log data
  • Running petrophysical calculations (Vshale, porosity, Sw, permeability)
  • Building lithology classifications from log responses
  • Correlating formations across multiple wells
  • Generating composite log displays or 3D well visualizations

Use individual domain skills when:

  • Only reading/writing LAS files (use lasio alone)
  • Only parsing DLIS data (use dlisio alone)
  • Only making stereonet plots from oriented data (use mplstereonet)

Common Issues

IssueSolution
LAS encoding errorsUse lasio.read(f, encoding='latin-1')
Curves have different depth samplingResample with welly or np.interp
Negative porosity valuesFlag invalid samples and check matrix/fluid density assumptions
Sw > 1.0 from ArchieCheck Rw, Archie parameters; use clay-corrected model
Vshale > 1 in hot shalesApply non-linear Vshale correction (Larionov)
DLIS multi-frame confusionIterate f.frames to find correct frame with target channels

Frequently asked questions

What does the Well Log Evaluation AI skill do?

Complete well log evaluation workflow from LAS/DLIS loading through QC, petrophysical analysis, lithology classification, and visualization. Use when performing formation evaluation from well log data.

Why use Well Log Evaluation on TypingMind?

Because you install it once and use it with any model. Well Log Evaluation is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Well Log Evaluation in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/SteadfastAsArt/geoscience-skills/tree/main/workflows/well-log-evaluation. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Well Log Evaluation?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Well Log Evaluation?

As many as you like. As long as a model supports skills, you can use Well Log Evaluation with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Well Log Evaluation AI skill free?

Yes. It is published on GitHub by SteadfastAsArt under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇