# agilescientific/welly architecture

> Architecture diagram of the GitHub repository agilescientific/welly, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-23). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/agilescientific/welly
- Repository: https://github.com/agilescientific/welly

## Overview

1. **What this repository is**
   `welly` is a Python library for working with subsurface well data at the “well” level, not just raw LAS files. Its central abstraction is a `Well` object that can collect logs, metadata, deviation surveys, tops, striplogs, and synthetic/seismic-related products.

2. **Core domain model**
   The main runtime objects appear to be:
   - `Well` for a single well
   - `Curve` for individual log curves
   - `Project` for a collection of wells
   - `Location` and `CRS` for spatial positioning and coordinate reference handling
   - `Header` and LAS-related helpers for metadata
   These objects form the user-facing API and are the main boundaries for the architecture diagram.

3. **Data ingestion and LAS-centered I/O**
   LAS handling is the primary ingress/egress path. The package uses `lasio` conceptually and likely directly for parsing/writing LAS files, while `welly.las` and `welly.header` provide library-specific adaptation. Example files in `tests/assets`, `tutorial/data`, and `docs/_userguide` show that LAS is the dominant interchange format.

4. **Well assembly flow**
   A typical flow is: LAS file or related survey data is loaded into a `Well`, which then exposes logs through `w.data[...]`. Additional files such as deviation surveys and tops can be associated with the same well. `Project.from_las(...)` indicates a batch-loading path that builds many `Well` objects from a file pattern.

5. **Curve-centric processing**
   `curve.py`, `scales.py`, `defaults.py`, `fields.py`, and `utils.py` suggest a set of helpers for normalizing curve names, units, display scales, and default behaviors. This is the layer where raw log data is cleaned, standardized, and made plot-ready or analysis-ready.

6. **Quality and validation**
   `quality.py` is a separate subsystem for assessing log or well data quality. This is important architecturally because validation is not embedded in ingestion alone; it is a distinct stage that can be run on already-created `Well`/`Curve` objects.

7. **Spatial and directional context**
   `location.py` and `crs.py` handle position, coordinate system, and likely trajectory/deviation-related concerns. The presence of CSV/XLSX deviation survey examples in tests and tutorials shows that the library supports directional wells and needs a dedicated geometry/spatial boundary beyond simple log curves.

8. **Derived products and analysis helpers**
   `synthetic.py` indicates support for generated or modeled outputs, likely synthetic seismograms or related well-based derived traces. `canstrat.py` and `canstrat_codes.py` suggest one specialized classification/encoding subsystem for lithostratigraphic or cuttings-related descriptions.

9. **Visualization layer**
   `plot.py` is a distinct presentation subsystem. The README’s quick start shows plotting directly from a curve object, so plotting is designed as a first-class capability attached to the domain objects rather than a separate application layer.

10. **Package structure and dependency boundaries**
   The package is organized as a single Python library under `welly/`, with a relatively clean separation between domain objects, I/O, plotting, and utilities. The main external integration point visible from the tree is `lasio`; beyond that, the architecture is mostly self-contained within the library.

11. **Documentation and examples**
   `docs/` and `tutorial/` contain notebooks and Sphinx docs that double as executable architecture examples. They are not production subsystems, but they are important for understanding intended object flows: load well data, inspect curves, plot, relate wells in a project, and work with directional/location data.

12. **Tests as behavioral contracts**
   The `tests/` tree is broad and maps closely to the core modules: `test_well`, `test_curve`, `test_project`, `test_las`, `test_location`, `test_quality`, `test_plots`, `test_synthetic`, and `test_canstrat`. This indicates the architecture is organized around independently testable subsystems with explicit expected behavior at their boundaries.

13. **Build and release plumbing**
   GitHub Actions workflows cover tests, documentation builds, and PyPI release. `pyproject.toml` and `requirements.txt` define packaging/dependency management. These are support systems rather than runtime architecture, but they indicate the library is meant to be distributable as a standard Python package.

14. **Overall runtime shape**
   At runtime, the library is essentially a data-processing toolkit: ingest well files and auxiliary survey data, normalize into `Well`/`Curve`/`Project` objects, apply quality/utility/analysis functions, and optionally visualize or export results. The key architectural boundary is between external file formats and the internal well-domain object model.

Main entry points: [`welly/well.py`](https://github.com/agilescientific/welly/blob/main/welly/well.py) (Well), [`welly/curve.py`](https://github.com/agilescientific/welly/blob/main/welly/curve.py) (Curve), [`tests/test_well.py`](https://github.com/agilescientific/welly/blob/main/tests/test_well.py) (Tests), [`welly/project.py`](https://github.com/agilescientific/welly/blob/main/welly/project.py) (Project)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_core["Core domain"]
  node_welly["welly<br/>[__init__.py]"]
  node_well["Well<br/>domain object<br/>[well.py]"]
  node_project["Project<br/>collection<br/>[project.py]"]
  node_curve["Curve<br/>[curve.py]"]
end

subgraph group_io["I/O and metadata"]
  node_header["Header<br/>metadata<br/>[header.py]"]
  node_las["LAS I/O<br/>file adapter<br/>[las.py]"]
end

subgraph group_geo["Spatial context"]
  node_location["Location<br/>spatial model<br/>[location.py]"]
  node_crs["CRS<br/>coordinate system<br/>[crs.py]"]
end

subgraph group_analysis["Analysis helpers"]
  node_defaults["Defaults<br/>curve config<br/>[defaults.py]"]
  node_fields["Fields<br/>curve config<br/>[fields.py]"]
  node_scales["Scales<br/>display config<br/>[scales.py]"]
  node_utils["Utils<br/>helpers<br/>[utils.py]"]
  node_quality{{"Quality<br/>validation<br/>[quality.py]"}}
  node_synthetic["Synthetic<br/>derived product<br/>[synthetic.py]"]
  node_canstrat["Canstrat<br/>classification<br/>[canstrat.py]"]
  node_canstrat_codes["Codes<br/>code tables<br/>[canstrat_codes.py]"]
  node_plot["Plot<br/>visualization<br/>[plot.py]"]
end

subgraph group_docs["Examples and docs"]
  node_docs["Docs<br/>documentation<br/>[index.rst]"]
  node_tutorial["Tutorials<br/>examples<br/>[01_Well.ipynb]"]
  node_tests["Tests<br/>behavioral specs<br/>[test_well.py]"]
end

node_welly -->|"exports"| node_well
node_welly -->|"exports"| node_project
node_welly -->|"exports"| node_curve
node_well -->|"contains"| node_curve
node_well -->|"uses"| node_header
node_well -->|"uses"| node_location
node_well -.->|"checks"| node_quality
node_project -->|"contains"| node_well
node_project -->|"loads"| node_las
node_las -->|"adapts"| node_header
node_las -->|"reads/writes"| node_curve
node_location -->|"references"| node_crs
node_curve -->|"normalizes"| node_defaults
node_curve -->|"maps"| node_fields
node_curve -->|"formats"| node_scales
node_curve -->|"uses"| node_utils
node_quality -->|"analyzes"| node_well
node_quality -->|"analyzes"| node_curve
node_synthetic -->|"derives from"| node_well
node_canstrat -->|"uses"| node_canstrat_codes
node_plot -->|"renders"| node_curve
node_plot -->|"renders"| node_well
node_docs -.->|"includes"| node_tutorial
node_tests -.->|"covers"| node_well
node_tests -.->|"covers"| node_project
node_tests -.->|"covers"| node_curve
node_tests -.->|"covers"| node_las
node_tests -.->|"covers"| node_location
node_tests -.->|"covers"| node_quality
node_tests -.->|"covers"| node_plot
node_tests -.->|"covers"| node_synthetic
node_tests -.->|"covers"| node_canstrat

click node_welly "https://github.com/agilescientific/welly/blob/main/welly/__init__.py"
click node_well "https://github.com/agilescientific/welly/blob/main/welly/well.py"
click node_project "https://github.com/agilescientific/welly/blob/main/welly/project.py"
click node_curve "https://github.com/agilescientific/welly/blob/main/welly/curve.py"
click node_header "https://github.com/agilescientific/welly/blob/main/welly/header.py"
click node_las "https://github.com/agilescientific/welly/blob/main/welly/las.py"
click node_location "https://github.com/agilescientific/welly/blob/main/welly/location.py"
click node_crs "https://github.com/agilescientific/welly/blob/main/welly/crs.py"
click node_defaults "https://github.com/agilescientific/welly/blob/main/welly/defaults.py"
click node_fields "https://github.com/agilescientific/welly/blob/main/welly/fields.py"
click node_scales "https://github.com/agilescientific/welly/blob/main/welly/scales.py"
click node_utils "https://github.com/agilescientific/welly/blob/main/welly/utils.py"
click node_quality "https://github.com/agilescientific/welly/blob/main/welly/quality.py"
click node_synthetic "https://github.com/agilescientific/welly/blob/main/welly/synthetic.py"
click node_canstrat "https://github.com/agilescientific/welly/blob/main/welly/canstrat.py"
click node_canstrat_codes "https://github.com/agilescientific/welly/blob/main/welly/canstrat_codes.py"
click node_plot "https://github.com/agilescientific/welly/blob/main/welly/plot.py"
click node_docs "https://github.com/agilescientific/welly/blob/main/docs/index.rst"
click node_tutorial "https://github.com/agilescientific/welly/blob/main/tutorial/01_Well.ipynb"
click node_tests "https://github.com/agilescientific/welly/blob/main/tests/test_well.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_welly,node_well,node_project,node_curve toneBlue
class node_header,node_las toneAmber
class node_location,node_crs toneMint
class node_defaults,node_fields,node_scales,node_utils,node_quality,node_synthetic,node_canstrat,node_canstrat_codes,node_plot toneRose
class node_docs,node_tutorial,node_tests toneIndigo
```

## Components

### Core domain

Primary well object model and collection boundaries.

- [welly](https://github.com/agilescientific/welly/blob/main/welly/__init__.py): package · Top-level Python package and public API surface. · `welly/__init__.py`
- [Well](https://github.com/agilescientific/welly/blob/main/welly/well.py): domain object · Central well-level container for logs, tops, surveys, and derived products. · `welly/well.py`
- [Project](https://github.com/agilescientific/welly/blob/main/welly/project.py): collection · Manages sets of wells and batch assembly workflows. · `welly/project.py`
- [Curve](https://github.com/agilescientific/welly/blob/main/welly/curve.py): log curve · Represents individual curves and curve-level operations. · `welly/curve.py`

### I/O and metadata

LAS ingestion/export and well metadata adaptation.

- [Header](https://github.com/agilescientific/welly/blob/main/welly/header.py): metadata · Well and LAS header metadata handling. · `welly/header.py`
- [LAS I/O](https://github.com/agilescientific/welly/blob/main/welly/las.py): file adapter · LAS parsing, writing, and well assembly from LAS sources. · `welly/las.py`

### Spatial context

Location and coordinate reference handling for directional wells.

- [Location](https://github.com/agilescientific/welly/blob/main/welly/location.py): spatial model · Well position and surface/location data. · `welly/location.py`
- [CRS](https://github.com/agilescientific/welly/blob/main/welly/crs.py): coordinate system · Coordinate reference system support. · `welly/crs.py`

### Analysis helpers

Curve normalization, quality checks, derived products, and stratigraphic coding.

- [Defaults](https://github.com/agilescientific/welly/blob/main/welly/defaults.py): curve config · Default curve behavior and library conventions. · `welly/defaults.py`
- [Fields](https://github.com/agilescientific/welly/blob/main/welly/fields.py): curve config · Canonical field names and naming conventions. · `welly/fields.py`
- [Scales](https://github.com/agilescientific/welly/blob/main/welly/scales.py): display config · Curve scaling and display conventions. · `welly/scales.py`
- [Utils](https://github.com/agilescientific/welly/blob/main/welly/utils.py): helpers · Shared helper functions used across the package. · `welly/utils.py`
- [Quality](https://github.com/agilescientific/welly/blob/main/welly/quality.py): validation · Quality assessment for logs and well data. · `welly/quality.py`
- [Synthetic](https://github.com/agilescientific/welly/blob/main/welly/synthetic.py): derived product · Synthetic or modeled well-based outputs. · `welly/synthetic.py`
- [Canstrat](https://github.com/agilescientific/welly/blob/main/welly/canstrat.py): classification · Specialized lithostratigraphic / cuttings code handling. · `welly/canstrat.py`
- [Codes](https://github.com/agilescientific/welly/blob/main/welly/canstrat_codes.py): code tables · Canonical Canstrat code definitions and lookup tables. · `welly/canstrat_codes.py`
- [Plot](https://github.com/agilescientific/welly/blob/main/welly/plot.py): visualization · Plotting and presentation for curves and wells. · `welly/plot.py`

### Examples and docs

Executable usage examples and documentation assets.

- [Docs](https://github.com/agilescientific/welly/blob/main/docs/index.rst): documentation · User guide notebooks and rendered documentation assets. · `docs/index.rst`
- [Tutorials](https://github.com/agilescientific/welly/blob/main/tutorial/01_Well.ipynb): examples · Worked notebooks showing typical library workflows. · `tutorial/01_Well.ipynb`
- [Tests](https://github.com/agilescientific/welly/blob/main/tests/test_well.py): behavioral specs · Test suite covering core domain, I/O, plotting, and helpers. · `tests/test_well.py`

## Connections

- welly → Well: exports · Public package surface centers on Well.
- welly → Project: exports · Package exposes collection-level workflows.
- welly → Curve: exports · Package exposes curve-level API.
- Well → Curve: contains · A well aggregates one or more curves.
- Well → Header: uses · Well metadata is managed through header objects.
- Well → Location: uses · Well carries spatial/location context.
- Well → Quality: checks · Well objects can be assessed for quality.
- Project → Well: contains · Projects are collections of wells.
- Project → LAS I/O: loads · Batch project creation can start from LAS files.
- LAS I/O → Header: adapts · LAS I/O maps file metadata into library headers.
- LAS I/O → Curve: reads/writes · Curves are the primary data exchanged through LAS.
- Location → CRS: references · Locations depend on coordinate reference handling.
- Curve → Defaults: normalizes · Curve defaults define standard behaviors.
- Curve → Fields: maps · Curve naming uses canonical field mappings.
- Curve → Scales: formats · Curve display scaling is controlled separately.
- Curve → Utils: uses · Shared helpers support curve operations.
- Quality → Well: analyzes · Quality routines operate on well objects.
- Quality → Curve: analyzes · Quality routines also inspect curves directly.
- Synthetic → Well: derives from · Synthetic products are built from well data.
- Canstrat → Codes: uses · Classification logic depends on code tables.
- Plot → Curve: renders · Plotting is first-class at curve level.
- Plot → Well: renders · Plots can also be produced from wells.
- Docs → Tutorials: includes · Documentation is reinforced by worked notebooks.
- Tests → Well: covers · Tests validate core well behavior.
- Tests → Project: covers · Tests validate project workflows.
- Tests → Curve: covers · Tests validate curve behavior.
- Tests → LAS I/O: covers · Tests validate LAS ingestion and export.
- Tests → Location: covers · Tests validate spatial and directional behavior.
- Tests → Quality: covers · Tests validate quality checks.
- Tests → Plot: covers · Tests validate plotting behavior.
- Tests → Synthetic: covers · Tests validate synthetic output generation.
- Tests → Canstrat: covers · Tests validate Canstrat support.
