Skip to main content

Sucker Rod Design Library

Project description

libzrod

Sucker Rod Design Library (Wave Equation / Gibbs / Everitt-Jennings)

A wave equation library for sucker rod pump design and analysis, written in C/C++ and wrapped in Python.

Overview

libzrod solves the 1D damped wave equation to calculate dynamometer cards for both diagnostic (measured card in, pump card out) and predictive (parameters in, surface + pump cards out) analysis of sucker rod pumping systems. The core engine is cross-platform C++, exposed to Python via ctypes.

Key capabilities:

  • Diagnostic analysis: transform a measured surface dynamometer card into a downhole pump card
  • Predictive analysis: generate surface and pump cards from well parameters (rod string, pump, fluid, geometry)
  • Rod loading analysis: max/min stress per rod section with Modified Goodman limits
  • Pump velocity and chamber pressure visualization
  • Multi-format file I/O (.dyn, .rsdx/.rsvx, .inp6/.inp6e, .qrd, .zrod, .DAT)
  • Cloud design management (save, fetch, share via AWS)

Installation

pip install libzrod

Requirements: Python 3.9 - 3.13, numpy. Supported platforms: Windows (x86_64), macOS (x86_64/ARM), Linux (x86_64).

Authorization

An account is required to use the library:

  1. Create an account at zrod.io
  2. Email for manual authorization of your trial account (account creation is not monitored)
  3. Note: The beta library includes time restrictions

Or see the Colab Example for a quick demo.

Quick Start

from libzrod import zrod, TaperBase_t, TubingBase_t, WaveParams_t
import numpy as np

# Create engine (singleton — only one instance allowed)
myzrod = zrod()
myzrod.Login("username", "password")

# Configure well parameters
waveParams = myzrod.GetWaveParams()
waveParams.WellDepth = 8000              # feet
waveParams.diagSpm = 6.0                 # strokes per minute
waveParams.predSpm = 6.0
waveParams.diagDampUp = 0.05             # upstroke damping factor
waveParams.diagDampDn = 0.05             # downstroke damping factor
waveParams.predDampUp = 0.05
waveParams.predDampDn = 0.05
waveParams.predFo = 2000                 # predicted fluid load (lbs)
myzrod.SetWaveParams(waveParams)

# Define rod string (3-taper example)
tarr = (TaperBase_t * 3)()
tarr[0] = TaperBase_t(id=b"", L=1000, D=0.875, W=2.224, E=30500000, R=492)
tarr[1] = TaperBase_t(id=b"", L=1700, D=0.750, W=1.630, E=30500000, R=492)
tarr[2] = TaperBase_t(id=b"", L=300,  D=1.500, W=6.500, E=30500000, R=492)
myzrod.xSetDiagTapers(tarr, 1.0)         # 1.0 = fluid specific gravity
myzrod.xSetPredTapers(tarr, 1.0)

# Define tubing
tuarr = (TubingBase_t * 1)()
tuarr[0] = TubingBase_t(L=8000, innerDiameter=2.992, outerDiameter=3.500, weight=9.3, W=2.904, E=30500000, R=490)
myzrod.xSetDiagTubings(tuarr)
myzrod.xSetPredTubings(tuarr)

# Load a measured surface card
myzrod.LoadDynFromDAT("SX4D05B.DAT")     # .DAT format parser (Python-only)
# Or: myzrod.LoadDyn(spm, position_array, load_array)
# Or: myzrod.ParseDesignFile("wellfile.zrod")

# Run the wave equation solver
if myzrod.RunDesign():
    # Retrieve diagnostic results (measured card → pump card)
    (surfX, surfY) = myzrod.GetMeasuredDyno()       # surface card (position, load)
    (pumpX, pumpY) = myzrod.GetMeasuredPump()        # calculated pump card

    # Retrieve upscaled (curve-fitted) diagnostic
    (upscX, upscY) = myzrod.GetUpscaledDyno()
    (upscPX, upscPY) = myzrod.GetUpscaledPump()

    # Retrieve predictive results
    (predDynX, predDynY) = myzrod.GetPredDyno()      # predicted surface card
    (predPmpX, predPmpY) = myzrod.GetPredPump()       # predicted pump card

    # Numeric results
    results = myzrod.GetWaveResults()
    print(f"Diag Fo: {results.diag.FoSKr:.0f} lbs")
    print(f"Pred pump stroke: {results.pred.PumpStrokeNet:.2f} in")

API Reference

Initialization & Auth

Method Description
zrod() Create engine instance (singleton)
Login(username, password) -> bool Authenticate with zrod.io
Logout() -> bool End session
SetClientVersion(platform, major, minor, rev, build) Set client identifier
GetZrodVersion() -> np.ndarray Get C++ library version [major, minor, rev, build]
GetZrodVersionString() -> str Get version as "M.m.r.b" string

Configuration

Method Description
GetWaveParams() -> WaveParams_t Get current wave parameters
SetWaveParams(params) -> bool Set wave parameters
GetWaveSettings() -> WaveSettings_t Get advanced solver settings
SetWaveSettings(settings) -> bool Set advanced solver settings
xSetDiagTapers(tapers, fluidSG) -> bool Set diagnostic rod string (infers count)
xSetPredTapers(tapers, fluidSG) -> bool Set predictive rod string (infers count)
SetDiagTapers(tapers, count, fluidSG) -> bool Set diagnostic rod string (manual count)
SetPredTapers(tapers, count, fluidSG) -> bool Set predictive rod string (manual count)
xSetDiagTubings(tubings) -> bool Set diagnostic tubing string (infers count)
xSetPredTubings(tubings) -> bool Set predictive tubing string (infers count)
SetDiagTubings(tubings, count) -> bool Set diagnostic tubing string (manual count)
SetPredTubings(tubings, count) -> bool Set predictive tubing string (manual count)
xSetCasings(casings) -> bool Set casing string (infers count)
SetCasings(casings, count) -> bool Set casing string (manual count)
SetDiagApiTaperByNumber(num, pumpDia, pumpDepth) -> bool Set diagnostic taper from API rod number
SetPredApiTaperByNumber(num, pumpDia, pumpDepth) -> bool Set predictive taper from API rod number
SetPuApi(puApi) -> bool Set pumping unit geometry
SetPuInfo(puInfo) -> bool Set pumping unit info (with designation)
SetPuByName(name) -> bool Set pumping unit by database name
SetFourierCoeffCountPos(count) Set Fourier coefficients for position curve fitting
SetFourierCoeffCountLoad(count) Set Fourier coefficients for load curve fitting
SetUpscaledDynoPointCount(count) Set upscaled output resolution

Calculation

Method Description
RunDesign() -> bool Execute wave equation solver (diagnostic + predictive)
CalculateFo() -> float Calculate fluid load from pump/pressure parameters (lbs)
CalculateKrToDepth(depth) -> float Calculate rod spring constant to a given depth
ValidateDesign() -> list[dict] Validate current design, returns list of issues

Results — Diagnostic

Method Returns Description
GetMeasuredDyno() (pos, load) Measured surface card
GetMeasuredPump() (pos, load) Calculated downhole pump card
GetMeasuredPumpColors() np.ndarray[int32] Pump valve state colors per point
GetMeasuredPumpVelocity() np.ndarray Plunger velocity (in/sec)
GetMeasuredPumpVelocityNormalized() np.ndarray Plunger velocity (0-100 scale)
GetMeasuredPumpChamberPressure() np.ndarray Chamber pressure (psi)
GetMeasuredPumpChamberPressureNormalized() np.ndarray Chamber pressure (0-100 scale)
GetUpscaledDyno() (pos, load) Curve-fitted surface card
GetUpscaledPump() (pos, load) Pump card from curve-fitted input
GetUpscaledPumpColors() np.ndarray[int32] Valve state colors
GetUpscaledPumpVelocity() np.ndarray Plunger velocity
GetUpscaledPumpVelocityNormalized() np.ndarray Plunger velocity (0-100)
GetUpscaledPumpChamberPressure() np.ndarray Chamber pressure
GetUpscaledPumpChamberPressureNormalized() np.ndarray Chamber pressure (0-100)

Results — Predictive

Method Returns Description
GetPredDyno() (pos, load) Predicted surface card
GetPredPump() (pos, load) Predicted pump card
GetPredPumpColors() np.ndarray[int32] Valve state colors
GetPredPumpVelocity() np.ndarray Plunger velocity
GetPredPumpVelocityNormalized() np.ndarray Plunger velocity (0-100)
GetPredPumpChamberPressure() np.ndarray Chamber pressure
GetPredPumpChamberPressureNormalized() np.ndarray Chamber pressure (0-100)

Results — Rod Loading

Method Returns Description
xGetMeasuredRodLoading() (depth, lbsMax, lbsMin, pctMax, pctMin) Measured rod loading per section
xGetUpscaledRodLoading() (depth, lbsMax, lbsMin, pctMax, pctMin) Upscaled rod loading
xGetPredRodLoading() (depth, lbsMax, lbsMin, pctMax, pctMin) Predicted rod loading

Results — Other

Method Returns Description
GetWaveResults() WaveResults_t Numeric results (Fo, Kr, pump stroke, production, etc.)
GetWaveParamsReadOnly() WaveParamsReadOnly_t Computed parameters (point counts, DT, buoyancy)
GetIntermediateCard(nodeindex, dynotype) (pos, load) FEA node card (dynotype: 1=meas, 2=upsc, 3=pred)
GetIntermediateTimeSlice(timestep, dynotype) (pos, load) All nodes at one timestep
GetPermissibleLoads(destX, destY, count, clipmin, clipmax) bool Modified Goodman envelope

File I/O

Method Description
LoadDyn(spm, pos_array, load_array) -> bool Load measured card from arrays
LoadDynFromFile(filepath) -> bool Load .dyn file
LoadDynFromFileContents(text) -> bool Load .dyn from string
LoadDynFromDAT(filepath) -> bool Load .DAT format (Python-only parser)
ParseDesignFile(filepath) -> bool Parse design file (.zrod, .rsdx, .inp6, etc.)
ParseDesignFileContents(contents, ftype) -> bool Parse from string
WriteDesignFile(filepath) -> bool Write .zrod design file
WriteDesignFileWithTemplate(filepath, templatepath) -> bool Write with template

Design Management (Cloud)

Note: Cloud design management is a work in progress and subject to change.

Method Description
FetchDesigns(fromserver) -> int Fetch design list (True=server, False=cached). Returns count.
GetDesigns() -> list[DesignInfo] Get list of DesignInfo objects
GetDesign(designId) -> bool Load a design by ID
SaveCurrentDesign(overwrite) -> bool Save current design to cloud
SubmitDesign(email, nonblocking) -> bool Submit design for review
DeleteDesign(designId) -> bool Delete a cloud design
SetDesignTitle(title) -> bool Set design title
GetDesignTitle() -> str Get design title
SetComment(comment) -> bool Set design comment
GetComment() -> str Get design comment
GetDesignID() -> str Get current design ID (compact UUID)

Metadata & Debug

Method Description
GetPuInfo() -> PuInfo_t Get pumping unit info
GetCasingCount() -> int Get casing section count
GetCasings() -> list[CasingBase_t] Get casing sections
GetDeviationSurveyCount() -> int Get deviation survey point count
GetDeviationSurvey() -> list[DeviationSurveyPoint_t] Get deviation survey
PrintZrodObj() Print internal state to console
DebugZrodObj(filepath) Dump debug info to file (if available)

Data Structures

TaperBase_t — Rod Section

Field Type Unit Description
id bytes[32] Rod grade identifier (e.g. b"D")
L float feet Section length
D float inches Rod body diameter
W float lb/ft Weight per foot
T float psi Minimum tensile strength
E float psi Young's modulus (typically 30,500,000)
R float lb/ft^3 Density (typically 490 for steel)
RL float feet Individual rod length for UI (default 25)
K float Modified Goodman K constant (default 2.8)
M float Modified Goodman M constant (default 0.375)

TubingBase_t — Tubing Section

Field Type Unit Description
L float feet Section length
innerDiameter float inches Tubing ID
outerDiameter float inches Tubing OD
weight float lb/ft Weight per foot
W float lb/ft Rod-in-tubing weight factor
T float psi Tensile strength
E float psi Young's modulus
R float lb/ft^3 Density

WaveParams_t — Core Parameters

Key fields (see CLAUDE.md for full list):

Field Type Unit Description
WellDepth float feet Total well depth
diagSpm / predSpm float SPM Strokes per minute
diagDampUp / diagDampDn float Damping factors (0.0–1.0, typical 0.05)
predDampUp / predDampDn float Predictive damping factors
diagFluidSG / predFluidSG float Fluid specific gravity
diagPumpPlungerDiameter float inches Plunger diameter
diagPumpDepth / predPumpDepth float feet Pump setting depth
predFo float lbs Target fluid load (or use CalculateFo())
predFillage float % Pump fillage (0–100)
predCompression float Gas compression ratio
usePumpingUnitForPosition bool Use PU geometry for position (vs measured)

Naming Conventions

x-prefix methods (e.g. xSetDiagTapers, xGetMeasuredRodLoading) are Pythonic convenience wrappers:

  • xSet* infers the array count from len() and passes ctypes.byref() automatically
  • xGet* allocates numpy output arrays automatically and returns them

The non-x versions require you to pass count and pre-allocated arrays manually.

Workflow Patterns

Diagnostic + Predictive Analysis

1. zrod() → Login()
2. GetWaveParams() → set fields → SetWaveParams()
3. xSetDiagTapers() + xSetPredTapers()
4. xSetDiagTubings() + xSetPredTubings()
5. LoadDyn() or LoadDynFromDAT() or ParseDesignFile()
6. RunDesign()
7. GetMeasuredDyno(), GetMeasuredPump(), GetPredDyno(), GetPredPump()
8. GetWaveResults() for numeric output

Predictive-Only (No Measured Card)

1. zrod() → Login()
2. GetWaveParams() → set fields, usePumpingUnitForPosition=True → SetWaveParams()
3. SetPuApi() or SetPuByName()
4. xSetPredTapers(), xSetPredTubings()
5. CalculateFo() or set predFo manually
6. RunDesign()
7. GetPredDyno(), GetPredPump()

File Round-Trip

1. ParseDesignFile("input.zrod")    # loads all parameters + measured card
2. RunDesign()
3. WriteDesignFile("output.zrod")   # saves current state

Constants

# Prediction algorithm types (for WaveSettings_t.predAlgorithmType)
# Note: Integer values are subject to change — use the PRED_ALGORITHM_* names.
PRED_ALGORITHM_STANDARD = 0       # Default
PRED_ALGORITHM_OLD = 1            # Legacy algorithm
PRED_ALGORITHM_EXPERIMENTAL = 2   # Experimental
PRED_ALGORITHM_LEAKAGE = 3       # With leakage modeling

Known Limitations

The following C API functions are not yet wrapped in the Python interface:

C Function Purpose
SetDeviationSurvey() Set wellbore deviation survey
SetDeviationSurveyWithMIA() Set deviation survey (interleaved format)
SetSaveIntermediateCards() Enable intermediate FEA node card output
SetStatusCallback() Async status callbacks
GetDiagTaperCount/GetPredTaperCount Query rod section counts
GetDiagTapers/GetPredTapers Retrieve rod sections
GetDiagTubingCount/GetPredTubingCount Query tubing section counts
GetDiagTubings/GetPredTubings Retrieve tubing sections

Platform Support

Platform Architecture Python Versions
Windows x86_64 3.9 - 3.13
macOS x86_64, ARM64 3.9 - 3.13
Linux x86_64 3.9 - 3.13

Mobile Apps

Beta access available for iOS and Android demo apps. Contact for access.

Web App

The ZROD web app demonstrates the full feature set of the library, including interactive dynamometer card visualization, rod loading analysis, pump velocity display, multi-format file import/export, and cloud design management.

Troubleshooting

RunDesign() returns False: Call ValidateDesign() to get a list of issues with codes and messages. Common causes: missing rod string, missing measured card (when usePumpingUnitForPosition=False), zero SPM, or invalid pump parameters.

Singleton warning: zrod is a singleton. Creating a second instance returns the same object with a warning. Use del myzrod before creating a new one if needed.

Platform binary not found: The library ships platform-specific binaries. Ensure your Python version and platform match a supported wheel.

Contact & Licensing

For licensing inquiries, reach out via LinkedIn.

Legal


*Help improve this document. Contact me with feedback or ambiguities.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

libzrod-0.1.28-cp314-cp314t-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp314-cp314-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp313-cp313-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp312-cp312-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp311-cp311-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp310-cp310-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

libzrod-0.1.28-cp39-cp39-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.28+ x86-64

File details

Details for the file libzrod-0.1.28-cp314-cp314t-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp314-cp314t-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 effd9bb6d650b1771da1132c67f8877c7b88ffd9d1cc800fe83ede4bdcacb189
MD5 5608bd9e2036a207331d429782753f30
BLAKE2b-256 8ad484c277ce28cf8bad02f887896503ca6aef74ec2bca6b02e587d813da2a8d

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp314-cp314-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp314-cp314-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 013de993025001287efd4f250f95fc0eaed48847a7031a45301ed2020bf6d66e
MD5 7af19622115f34c7fdccf135bcd72972
BLAKE2b-256 0d73d5cae8c887a15468e2bea797c9ea23991272910dd7e978c22c1b36d98bdf

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp313-cp313-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 7d13ad610a1fdeeaa8d020b0dd26c784311cd079a29b72a4050aa1324009deaf
MD5 e6e0baed33fe754e2d4b546a70aa5ea2
BLAKE2b-256 22bd2fdcdcdbf6b5b8cb6ec66f4e1fece44fb7626b087fdf682944c1b61af808

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c8f0cbcce359953e1c3db71f8eb9a1b6d5f965952063a7fdb36b7b1dcf9d3c22
MD5 58560a1e0e7da4e8ebba80f219736338
BLAKE2b-256 7b4b03f03b388a98b3ef7fe5d3fec515a9767e782b9c1129507d66b799333b6a

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 30da9ddd21ce805b2ccad70e09ddb31d91acfb7cf2f3650af1e2d5aff78058a8
MD5 dd2ed96e799f32d9043b4a480d6afa90
BLAKE2b-256 09ad7bbec275970fee3e6c396c04bb90c306e5e09e42bf7d74a7e87b79ee690e

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b7fe5206384bd27a59b1b2f8900d3e5897b723dcb52fcb43b33e5028be10856f
MD5 2be4e2a822491678edbd785de4a1f52d
BLAKE2b-256 dbc54da05439405fc351dfd02c05ebf5e041abcefac20300795ddf8930663511

See more details on using hashes here.

File details

Details for the file libzrod-0.1.28-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for libzrod-0.1.28-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e417f030852037622a9d620087cb150554182b542438c2ed3ee3f9aa58ffadf9
MD5 ff5167360a1b6adc22aaa92203795f0b
BLAKE2b-256 df123a5c56a47a6d8d13702e12a83628035f2ce7fb60cdb52cadcb4d428e8636

See more details on using hashes here.

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