Skip to main content

Parser for earthquake rupture forecasts like UCERF3 and 2023 NSHMP.

Project description

parserf

PyPI version Downloads Documentation Status CI pre-commit Coverage

parserf parses Earthquake Rupture Forecast (ERF) datasets into clean, structured Python objects — fault subsections, rupture scenarios, parent faults, and background seismicity. It loads and caches the raw USGS GeoJSON/CSV source files once and exposes enriched, ready-to-use tables and view objects, so downstream consumers (such as PSHA source-model builders) can pull exactly the faults and rupture/MFD information they need without re-deriving geometry, dimensions, or rollups.

Supported Models

FaultModel value Model
FaultModel.NSHMP_2023 USGS NSHM CONUS v6.0.0
FaultModel.UCERF3_31 UCERF3 fault model 3.1
FaultModel.UCERF3_32 UCERF3 fault model 3.2

Installation

parserf requires Python >=3.12.

pip install parserf

For example notebooks, install the optional examples extra. It adds ipykernel, jupyterlab, and matplotlib.

pip install "parserf[examples]"

In a uv project, you can add the package with:

uv add parserf

User Guide

Consider the package architecture:

            FaultModelDataset            <- data layer: load + cache raw/derived tables
          (subsections, ruptures,           (the single source of truth)
           parent_ids, grid)
                       |
       +---------------+-----------------------------+
       |               |                             |
   queries.py      single-entity views        batch selection
  (get data by     FaultSubsection            ParentSelection  (many parents at once)
   lat/lon)        ParentFault                GridSelection    (background grid near site)
                       |
                each facade exposes:
                .data      -> attributes (no rupture info)
                .ruptures  -> participating ruptures + MFDs

Two recurring ideas:

  • Facade + view split. FaultSubsection / ParentFault are thin facades that validate the index/name, then hand you .data (plain attributes) and .ruptures (rupture participation + MFDs). Use whichever half you need.
  • Queries are separate from data. Spatial lookups live in queries.py and all take the dataset as their first argument — they don't live on the dataset object itself.

1. Load a dataset

from parserf import FaultModel, FaultModelDataset

ds = FaultModelDataset(FaultModel.NSHMP_2023)

# Cached tables (each is a (Geo)DataFrame, lazily built and memoized):
ds.subsections       # every subsection: geometry, dip, depths, length/width/area, parent info
ds.ruptures          # rupture scenarios; subsection indices parsed into sets[int]
ds.parent_ids        # parent_name <-> parent_id map
ds.grid              # background gridded seismicity (lon, lat, style wts, rate per mag bin)

2. Typical queries

All query functions take ds first.

from parserf import (
    get_nearest_subsection_index,
    get_subsections_list,
    get_parents_list,
    get_ruptures_near,
)

# Given a fault name, what is the parent fault id?
pid = ds.get_parent_fault_id(name="Little Lake")

# Given a location, what is the closest subsection id?
idx = get_nearest_subsection_index(ds, lat=35.77, lon=-117.60)

# Can I get a list of all the subsection or parent fault indices within a site radius?
nearby_subs = get_subsections_list(ds, lat=35.77, lon=-117.60, dist_km=50.0)
parent_ids  = get_parents_list(ds, lat=35.77, lon=-117.60, dist_km=50.0)

# Can I get a list of all the rupture scenarios within a site radius?
rups_near = get_ruptures_near(ds, lat=35.77, lon=-117.60, dist_km=50.0)

3. Look at one subsection

from parserf import FaultSubsection

sub = FaultSubsection(ds, index=idx)

# .data — plain attributes
sub.data.name, sub.data.parent_name
sub.data.dip, sub.data.upper_depth_km, sub.data.lower_depth_km
sub.data.length_km, sub.data.width_km, sub.data.area_km2
sub.data.geometry          # shapely LineString of the surface trace
sub.data.geometry_3d       # shapely PolygonZ of the dipping surface (lon, lat, depth_km)

# .ruptures — participation + MFD
rups = sub.ruptures.participating_ruptures   # one row per rupture; .contributions = per-parent breakdown
cmfd  = sub.ruptures.cumulative_mfd           # columns: magnitude, cumulative_rate

4. Look at one parent fault

ParentFault takes the name and resolves it internally.

from parserf import ParentFault

flt = ParentFault(ds, name="Compton")

# .data
flt.data.subsections     # DataFrame of all child subsections
flt.data.geometry        # merged + oriented LineString (dips to the right as you walk along it)
flt.data.geometry_3d     # shapely PolygonZ of the dipping surface (lon, lat, depth_km)

# .ruptures
flt.ruptures.participating_ruptures   # one row per rupture; .contributions = per-parent breakdown
flt.ruptures.cumulative_mfds          # per child subsection: index, magnitude, cumulative_rate

Per-subsection scalars (dip, depths, areas) are intentionally not pre-aggregated at the parent level — read them from flt.data.subsections and aggregate as you see fit (e.g., area-weighted).

5. Batch selection (the downstream-model path)

Find parents near a site, then pull all of them in one rupture-table scan.

import pandas as pd

from parserf import ParentSelection, GridSelection

parent_ids = get_parents_list(ds, lat=35.77, lon=-117.60, dist_km=50.0)
sel = ParentSelection(ds, parent_ids)

sel.parents       # per-parent GeoDataFrame (indexed by parent_id): parent_name, geometry
sel.subsections   # all subsections for those parents (FULL extent — not radius-clipped)
sel.ruptures      # one row per rupture: m, rate, depth, dip, width, rake, geometry,
                  # length_km, area_km2, contributions

# Each rupture's `contributions` lists (parent_id, area_pct) for every parent it touches.
# To attribute rates to individual faults, explode that column into one row per (rupture, parent):
rups = sel.ruptures.explode("contributions")
rups[["parent_id", "area_pct"]] = pd.DataFrame(rups["contributions"].tolist(), index=rups.index)
rups["attributed_rate"] = rups["rate"] * rups["area_pct"] / 100.0   # full rate × that parent's area share

# Background seismicity near the same site (its own radius; grid extent may differ from faults)
gs = GridSelection(ds, lat=35.77, lon=-117.60, dist_km=100)
gs.grid           # grid points within 100 km, sorted nearest-first, with a dist_km column

FAQ

Why does contributions hold a list of tuples instead of one row per parent?

Rupture tables are one row per rupture, and rate is the full rupture rate. contributions keeps the per-parent area breakdown as (parent_id, area_pct) tuples. To get (rupture, parent) rows, use .explode("contributions"), then attribute rates with rate * area_pct / 100.

Why are some ruptures missing?

FaultModelDataset.ruptures drops zero-rate ruptures when it builds the parsed rupture table.

Data Development

Original Data Sources

Faults

Background grids

Derived Data

  • Parent fault information (parent_id and parent_name) is extracted from sections.geojson files.

Documentation

Full API docs are built with Sphinx and published on Read the Docs.

Credits

Portions of this code were generated or refined with the assistance of AI tools. The concept and code architecture/design are the original work of the author.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parserf-1.0.0.tar.gz (32.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parserf-1.0.0-py3-none-any.whl (32.9 MB view details)

Uploaded Python 3

File details

Details for the file parserf-1.0.0.tar.gz.

File metadata

  • Download URL: parserf-1.0.0.tar.gz
  • Upload date:
  • Size: 32.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for parserf-1.0.0.tar.gz
Algorithm Hash digest
SHA256 cde686fed125bcd24ef399746bd46f1be3cc8e4c70fb80991f21619acec02a0e
MD5 58afdd1ffeae7201d99753c75020fafb
BLAKE2b-256 22407c85bcf0eca05eed2c1d87bec8ca836bdc611098447a736f8ce1b06cdff6

See more details on using hashes here.

Provenance

The following attestation bundles were made for parserf-1.0.0.tar.gz:

Publisher: release.yml on asarmy/parserf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file parserf-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: parserf-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 32.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for parserf-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7fd759623510872f176f90de8b5971bb36a12c47785de9ecb1785b5f716a0695
MD5 c8165e4bfe0c24afad7f6e2284825bb9
BLAKE2b-256 5ecbf60cd25883922160cb2996e4f542c98e88bb5ccababcc0cd844ab1ca8360

See more details on using hashes here.

Provenance

The following attestation bundles were made for parserf-1.0.0-py3-none-any.whl:

Publisher: release.yml on asarmy/parserf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page