SeisCode Models
SeisCode Models is a lightweight Python library for generating, manipulating, visualizing, and exporting synthetic 2D subsurface velocity models.
It is designed for seismic modeling, seismic inversion experiments, resolution tests, and the preparation of velocity fields for numerical solvers, including eikonal solvers and finite-difference wave propagation codes.
Built on NumPy, the library provides geological model generators and an object-oriented interface for working with velocity fields.
Features
- Geological model generation: Create dipping layers, faulted strata, salt domes, sinusoidal interfaces, and low-velocity layers.
- Synthetic anomalies: Add Gaussian velocity anomalies to simulate heterogeneous subsurface structures.
- Customizable velocity fields: Generate vertical velocity gradients and checkerboard patterns for resolution tests.
- Object-oriented API: Build and manipulate models through the
VelocityModelclass. - Model processing: Apply fault offsets, clip velocity values, and smooth velocity fields.
- Numerical precision: Work with
float32orfloat64velocity arrays. - Visualization: Display velocity models with the built-in plotting utility.
- Data export and loading: Save models as raw binary or NumPy files for use in external applications.
- Lightweight dependencies: Requires NumPy and Matplotlib.
Installation
Install the latest published version from PyPI:
pip install seiscode-models
To install the development version from the repository:
git clone https://github.com/PageotD/seiscode-models.git
cd seiscode-models
pip install -e ".[dev]"
The development dependencies include pytest, pytest-cov, Ruff, and Python packaging tools.
Quick start
Generate a velocity model with a linear velocity gradient, add a Gaussian anomaly, inspect its properties, and visualize the result.
from seiscode_models import VelocityModel
# Generate a 2D velocity model.
model = VelocityModel.gradient(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
v0=1500.0,
v1=4500.0,
)
# Add a positive Gaussian velocity anomaly.
model.add_anomaly(
cx=100,
cz=50,
sigma_x=15,
sigma_z=10,
dv=1000.0,
)
# Inspect model properties.
print(model)
print(model.stats())
# Visualize the velocity field.
model.plot(title="Velocity Model with Gaussian Anomaly")
# Export the model as a NumPy file.
model.export("velocity_model.npy", format="npy")
The resulting velocity field is a NumPy array with shape (nx, nz). Velocity values are expressed in meters per second, while dx and dz represent grid spacing in meters.
The anomaly coordinates and standard deviations are specified in grid cells, not physical distances.
Generating geological models
VelocityModel provides class methods for creating several common synthetic subsurface structures.
All examples below use the public API.
Linear velocity gradient
Create a model in which velocity increases linearly with depth.
from seiscode_models import VelocityModel
model = VelocityModel.gradient(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
v0=1500.0,
v1=4500.0,
)
model.plot(title="Linear Velocity Gradient")
Parameters:
nx,nz: Number of grid cells along the horizontal and vertical axes.dx,dz: Grid spacing in meters.v0: Velocity at the top of the model, in m/s.v1: Velocity at the bottom of the model, in m/s.dtype: NumPy-compatible data type; defaults tonumpy.float32.
Dipping layers
Generate a stratified model with inclined geological interfaces.
model = VelocityModel.dipping_layers(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
v=(1800.0, 2400.0, 3200.0, 4200.0),
dip_deg=8.0,
)
model.plot(title="Dipping Geological Layers")
The v parameter specifies the velocity values associated with the layers, while dip_deg controls their dip angle.
Faulted layers
Create a stratified velocity model with a vertical fault offset.
model = VelocityModel.faulted_layers(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
ix_fault=120,
throw=8,
v=(1800.0, 2400.0, 3200.0, 4200.0),
)
model.plot(title="Faulted Geological Layers")
ix_fault: Horizontal grid index of the fault.throw: Vertical displacement in grid cells.v: Sequence of layer velocities in m/s.
Salt dome
Generate a synthetic salt structure embedded in sedimentary material.
model = VelocityModel.salt_dome(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
cx=140,
width=40.0,
v_salt=4500.0,
v_sed=2500.0,
)
model.plot(title="Salt Dome")
The dome's horizontal position is controlled by cx, and its approximate width by width. The velocities of the salt and surrounding sediments are configurable.
Sinusoidal interface
Create a two-layer model separated by a sinusoidal geological interface.
model = VelocityModel.sinusoidal_interface(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
period=100.0,
amplitude=8.0,
v_top=2000.0,
v_bottom=3500.0,
)
model.plot(title="Sinusoidal Interface")
Checkerboard model
Generate alternating velocity anomalies for resolution tests and inversion benchmarks.
model = VelocityModel.checkerboard(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
cell=20,
v0=3000.0,
dv=600.0,
)
model.plot(title="Checkerboard Resolution Model")
The cell parameter controls the checkerboard block size in grid cells. The two alternating velocity values are v0 + dv and v0 - dv.
Low-velocity layer
Introduce a buried low-velocity channel into a background velocity gradient.
model = VelocityModel.low_velocity_layer(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
k0=30,
thickness=8,
v_slow=1200.0,
)
model.plot(title="Buried Low-Velocity Layer")
k0: Starting vertical grid index of the low-velocity layer.thickness: Layer thickness in grid cells.v_slow: Velocity within the layer, in m/s.
Heterogeneous anomaly model
Generate a more complex synthetic model containing multiple velocity anomalies and smoothed random perturbations.
model = VelocityModel.heterogeneous_anomaly_model(
nx=384,
nz=122,
dx=10.0,
dz=10.0,
seed=7,
)
model.plot(title="Heterogeneous Velocity Model")
The seed parameter controls the random perturbations, allowing the same synthetic realization to be reproduced.
Modifying existing models
The VelocityModel class provides methods for modifying velocity fields in place. These methods return the model instance, allowing method chaining.
Add a Gaussian anomaly
Use add_gaussian_anomaly() to introduce a localized positive or negative velocity perturbation.
model = VelocityModel.gradient(nx=201, nz=101)
model.add_gaussian_anomaly(
cx=100,
cz=50,
sigma_x=15,
sigma_z=10,
dv=-500.0,
)
Parameters:
cx,cz: Anomaly center in grid cells.sigma_x,sigma_z: Gaussian standard deviations in grid cells.dv: Velocity perturbation at the anomaly center, in m/s.vmin,vmax: Minimum and maximum allowed velocities.
Add an elliptical inclusion
Use add_elliptical_inclusion() to introduce a localized velocity inclusion.
model = VelocityModel.gradient(nx=201, nz=101)
model.add_elliptical_inclusion(
cx=100,
cz=50,
radius_x=15.0,
radius_z=10.0,
cv=200.0,
)
Parameters:
cx,cz: Anomaly center in grid cells.radius_x,radius_z: Radius along x and z axis.cv: (constant) Velocity of the inclusion in m/s.
Apply a fault offset
model.add_fault(
ix_fault=100,
throw=8,
)
This applies a vertical displacement to the velocity field across the specified fault index.
Clip velocity values
Constrain the velocity field to a specified range.
model.clip(
vmin=500.0,
vmax=6000.0,
)
Smooth the velocity field
Apply a moving-average filter to reduce small-scale variations.
model.smooth(k=5)
The smoothing kernel size k must be an odd integer greater than or equal to 3. The array is edge-padded during filtering.
Chain operations
Since the modification methods return the model instance, they can be combined.
model = (
VelocityModel.dipping_layers(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
)
.add_anomaly(
cx=100,
cz=50,
sigma_x=12,
sigma_z=8,
dv=800.0,
)
.clip(vmin=500.0, vmax=6000.0)
.smooth(k=3)
)
model.plot(title="Processed Velocity Model")
These operations modify the existing model rather than creating independent copies.
Use copy() when an independent model is needed.
Accessing model properties
A VelocityModel instance exposes its underlying velocity array and grid metadata.
model = VelocityModel.gradient(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
)
print("Shape:", model.data.shape)
print("Horizontal cells:", model.nx)
print("Vertical cells:", model.nz)
print("Horizontal spacing:", model.dx)
print("Vertical spacing:", model.dz)
print("Data type:", model.dtype)
print("Minimum velocity:", model.vmin)
print("Maximum velocity:", model.vmax)
The stats() method returns a dictionary containing summary statistics.
statistics = model.stats()
for name, value in statistics.items():
print(f"{name}: {value}")
The returned dictionary contains:
| Key | Description |
|---|---|
shape |
Velocity array dimensions (nx, nz) |
dx |
Horizontal grid spacing in meters |
dz |
Vertical grid spacing in meters |
dtype |
NumPy data type |
vmin |
Minimum velocity in m/s |
vmax |
Maximum velocity in m/s |
vmean |
Mean velocity in m/s |
vstd |
Standard deviation of velocity in m/s |
Exporting and loading models
Velocity fields can be exported for use with external seismic modeling and inversion software.
Export a model
from seiscode_models import VelocityModel
model = VelocityModel.gradient(
nx=201,
nz=101,
dx=10.0,
dz=10.0,
)
# NumPy format: preserves array shape and data type.
model.export("velocity_model.npy", format="npy")
# Raw binary format.
model.export("velocity_model.bin", format="bin")
# Raw binary in Fortran memory order.
model.export(
"velocity_model_fortran.bin",
format="bin",
order="F",
)
Supported export formats:
| Format | Description |
|---|---|
npy |
NumPy binary format, preserving array shape and data type |
bin |
Raw binary velocity data |
raw |
Alias for raw binary export |
For raw binary files, the order parameter controls the memory layout:
C: C-contiguous, row-major ordering.F: Fortran-contiguous, column-major ordering.
Choose the layout expected by your numerical solver. Raw binary files do not contain array dimensions or grid-spacing metadata, so these must be tracked separately.
Load a model
The VelocityModel.load() class method can load a previously exported model.
For NumPy files:
model = VelocityModel.load(
"velocity_model.npy",
dx=10.0,
dz=10.0,
)
For raw binary files, provide the expected array shape and data type:
model = VelocityModel.load(
"velocity_model.bin",
shape=(201, 101),
dtype="float32",
dx=10.0,
dz=10.0,
)
The shape must match the dimensions used when exporting the model, and the data type must match the binary representation.
Working directly with NumPy
VelocityModel wraps a NumPy array, accessible through the data property.
import numpy as np
from seiscode_models import VelocityModel
model = VelocityModel.gradient(nx=201, nz=101)
velocity = model.data
print(type(velocity))
print(velocity.shape)
print(velocity.dtype)
# Example: compute the mean velocity along the vertical axis.
mean_velocity_by_column = np.mean(velocity, axis=1)
The array uses the convention (nx, nz), with the horizontal coordinate first and the vertical coordinate second.
This convention should be considered when passing the velocity field to external numerical solvers or plotting utilities.
Public API reference
The package exposes its principal classes and functions directly from seiscode_models.
Main class
| API | Description |
|---|---|
VelocityModel |
Represents a 2D subsurface velocity model |
Model constructors
| API | Description |
|---|---|
VelocityModel.gradient() |
Linear velocity gradient with depth |
VelocityModel.dipping_layers() |
Inclined geological layers |
VelocityModel.faulted_layers() |
Stratified model with a fault offset |
VelocityModel.salt_dome() |
Salt dome embedded in sediments |
VelocityModel.sinusoidal_interface() |
Two layers separated by a sinusoidal interface |
VelocityModel.checkerboard() |
Checkerboard pattern for resolution tests |
VelocityModel.low_velocity_layer() |
Buried low-velocity layer |
VelocityModel.heterogeneous_anomaly_model() |
Heterogeneous model with synthetic anomalies |
Model operations
| API | Description |
|---|---|
model.add_anomaly() |
Add a Gaussian velocity anomaly |
model.add_fault() |
Apply a fault offset |
model.clip() |
Clip velocities to specified bounds |
model.smooth() |
Smooth the velocity field |
model.copy() |
Create an independent copy of the model |
model.plot() |
Visualize the velocity field |
model.export() |
Export the velocity field to a file |
VelocityModel.load() |
Load a model from a supported file |
model.stats() |
Return summary statistics |
Additional public functions
The following functions are also available from the package's top-level namespace:
| Function | Description |
|---|---|
gradient_background() |
Generate a linear background velocity field |
add_gaussian_anomaly() |
Add a Gaussian anomaly to a NumPy velocity array |
add_fault_offset() |
Apply a fault displacement to a NumPy velocity array |
dipping_layers() |
Generate dipping layers |
sinusoidal_interface() |
Generate a sinusoidal interface |
faulted_layers() |
Generate faulted geological layers |
checkerboard() |
Generate a checkerboard model |
salt_dome() |
Generate a salt dome |
low_velocity_layer() |
Generate a buried low-velocity layer |
heterogeneous_anomaly_model() |
Generate a heterogeneous synthetic model |
parse_dtype() |
Normalize supported data type specifications |
validate_model() |
Validate a velocity model |
export_model() |
Export a NumPy velocity array |
load_model() |
Load velocity data from a file |
quick_view() |
Visualize a NumPy velocity array |
For example, the lower-level functions can be used without constructing a VelocityModel instance:
from seiscode_models import gradient_background
velocity = gradient_background(
nx=201,
nz=101,
v0=1500.0,
v1=4500.0,
)
These functions are useful when working directly with NumPy arrays or integrating model generation into an existing scientific workflow.
Running tests
To install the development dependencies:
pip install -e ".[dev]"
Run the test suite with pytest:
pytest
To run the tests with coverage reporting:
pytest --cov=seiscode_models --cov-report=term-missing
Requirements
- Python 3.8 or later
- NumPy 1.21 or later
- Matplotlib 3.5 or later
Contributing
Contributions, bug reports, and suggestions are welcome.
When contributing:
- Keep examples consistent with the actual public API.
- Add or update tests for behavioral changes.
- Run the test suite before submitting a pull request.
- Follow the project's existing code style.
License
This project is distributed under the MIT License. See LICENSE for details.
Citation
If you use SeisCode Models in academic research, please cite the software using the project's Zenodo record.
For the recommended citation format and version-specific metadata, consult the Zenodo record directly.
Metadata
Release files for seiscode-models 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| seiscode_models-0.5.0.tar.gz | 31.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| seiscode_models-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.5 kB
Release files / seiscode_models-0.5.0.tar.gz
| Download URL | seiscode_models-0.5.0.tar.gz |
|---|---|
| Size | 31.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5dd4045089c86fe21f8b6a57b30209174f37ad657fd6e2029e75995dd102cf04
|
|
BLAKE2b-256 checksum How to use checksums |
1e222e3392e12a6860143e09f6235b363a2b9e36ff626d9ebe4e7162d8040b2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / seiscode_models-0.5.0-py3-none-any.whl
| Download URL | seiscode_models-0.5.0-py3-none-any.whl |
|---|---|
| Size | 26.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
570bb08d03c46277971b418b1d2f8d1c73b99028c917b74a5abeb543487b23d9
|
|
BLAKE2b-256 checksum How to use checksums |
3625c33001c4ebcb3220a8dbd62617f0156cc17da27528202ee94c160eb5c473
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency log