API reference
Modules are listed from the case description and simulation inward to the physics kernels. All quantities are SI unless a name says otherwise.
DrillPyze
DrillPyze: a coupled axial-torsional drillstring dynamics simulator, torque & drag model and controller test bench. SI units throughout.
Case files and builder (config)
Case configuration: a plain, JSON-serialisable description of a simulation
case in SI units, and a builder that turns it into a Simulation.
The same structure is used by the user interface, scripts and (later) the data-driven agent, so a case can be saved, shared and reproduced:
from DrillPyze import config
cfg = config.well_a() # the example case
cfg['parameters']['friction']['mu_static_open'] = 0.5
sim = config.build(cfg) # initialised Simulation
config.save(cfg, 'case.json')
- DrillPyze.config.well_a()[source]
Synthetic Well A of Aarsnes & Shor (2018): vertical to 1500 m, build at 3 deg/30 m to 60 deg, then tangent; 230 m of 5-3/4” collars below 5” drill pipe; bit off bottom at 2500 m. Friction gives off-bottom stick-slip with a stiff top-drive controller.
- DrillPyze.config.build_well(cfg)[source]
Wellbore (survey, casing shoe, hole diameter) from the case well section.
- DrillPyze.config.build_drillstring(cfg)[source]
Drillstring from the case drillstring rows (listed from the bit up).
- DrillPyze.config.bit_parameters(b, hole_diameter=None)[source]
BitParameters from a config entry, translating pre-0.1 keys.
- DrillPyze.config.build_parameters(cfg, zeta_p=None, first_mode=None)[source]
ModelParameters from the case parameters section.
zeta_p (pipe impedance) and first_mode (first torsional mode, Hz) are needed to build the top-drive controller; without them the controller is left unset and the simulation uses the stiff controller.
- DrillPyze.config.make_controller(c, zeta_p, inertia, first_mode=None)[source]
Controller parameters from a controller config entry.
- DrillPyze.config.build_fluid(cfg)[source]
Fluid from the case fluid section (unknown keys are ignored).
- DrillPyze.config.build_formation(cfg)[source]
Formation from the config, or None when the case has no formation section.
- DrillPyze.config.first_torsional_mode(sim)[source]
Estimate of the first torsional mode (Hz): 1 / (4 * one-way travel time).
- DrillPyze.config.build(cfg, initialize=True)[source]
Build (and by default initialise) a
Simulationfrom a config dict.
Simulation (simulation)
User-facing simulator for the coupled axial-torsional drillstring model.
Workflow:
sim = Simulation(wellbore, drillstring, fluid, params) # set up
sim.initialize(bit_depth=3000.0, hole_depth=3005.0) # initialise
sim.step(5.0, omega_sp=60 * units.RPM) # step ...
sim.step(1.0, v_block=0.01) # ... and step again
df = sim.results() # recorded data
The simulation can be paused between step calls for as long as needed,
inputs can change between calls, and calls of any length give identical
results to one long call. This is the hook for live data streaming and for
controllers written in Python (call step at the controller sample rate
with motor_torque=...).
- class DrillPyze.simulation.Simulation(wellbore, drillstring, fluid=None, params=None, name='simulation', formation=None)[source]
Bases:
object- Parameters:
wellbore (Wellbore)
drillstring (Drillstring)
fluid (Fluid)
params (ModelParameters, optional)
name (str)
- initialize(bit_depth, hole_depth=None, dx=10.0, record_rate=100.0, refresh_distance=1.0)[source]
Discretise the string with the bit at
bit_depth(m) and start from rest, hanging freely from the block (statically balanced).- Parameters:
bit_depth (float) – Bit measured depth (m).
hole_depth (float, optional) – Hole measured depth (m). Defaults to
bit_depth(bit just touching bottom with zero WOB).dx (float) – Maximum cell length (m). Smaller is more accurate and slower; the time step scales with
dx.record_rate (float) – Rate (Hz) at which scalar channels are recorded.
refresh_distance (float) – Axial travel of the string (m) after which the cell geometry and static tension are re-evaluated.
- modal_frequencies()[source]
First axial and torsional natural frequencies (Hz) of the string held at the top and free at the bit: f_1 = 1 / (4 T), T the wave travel time.
- damping_summary(frequency=None)[source]
Predicted modal damping ratios per component and direction, at the reference frequency (default) or at
frequency(Hz):zeta_fluid = (k0 + k1_stokes H) / (2 omega) * s, H = 1/(1 + (f_c/f)^2) zeta_material = alpha H / (2 omega) + beta omega / 2 (Rayleigh / Kelvin-Voigt) zeta_numerical = pi f dx (1 - nu) / c (first-order Godunov)
with s = 1 at f_ref (the model’s frequency-independent Stokes coefficient).
zeta_fluid_truescales the Stokes part by sqrt(f/f_ref) as the physical layer would.
- update_parameters(params=None, **_)[source]
Replace model parameters mid-simulation (e.g. friction factors from an estimator). The state is untouched.
- step(duration, omega_sp=None, v_block=None, motor_torque=None, omega_td=None, wob_sp=None, flow_rate=None, inlet_temperature=None)[source]
Advance the simulation by
durationseconds with inputs held constant. Inputs not given keep their previous values.- Top drive (choose one; the most recently given one sets the mode):
omega_spspeed set point (rad/s) for the internal controllermotor_torquemotor torque (N m) from an external controlleromega_tdprescribed top-drive speed (rad/s), e.g. measured RPM- Drawworks (choose one):
v_blockblock velocity (m/s, positive lowering)wob_spWOB set point (N) for the autodriller- Circulation (hydraulics and wellbore temperature):
flow_ratepump rate (m^3/s)inlet_temperaturemud temperature entering the drillstring (C)
Inputs without a controller (prescribed speed, block velocity, pump rate, inlet temperature) approach a new value linearly over a short ramp time (
params.ramps; 0 = instant), starting from the current value – or, when taking over from another mode, from the present physical value. Controlled set points (omega_sp,wob_sp) are not ramped by default: the controller shapes the response.Returns a dict of the latest scalar values.
- property time
Simulated time (s).
- tare_hookload()[source]
Zero the weight indicator: take the present hookload as the off-bottom reference, so surface WOB = reference - hookload (used by the autodriller).
- property hookload_reference
Off-bottom reference hookload (N) for surface WOB.
- hydraulics_results()[source]
Hydraulics channels, one row per ~1 s slow tick: standpipe pressure
spp, bottomhole pressurep_bh(Pa gauge),ecd(kg/m^3), pump rateq_in, return flowq_out, bit flowq_bit(m^3/s), bit pressure dropdp_bit, surface loss and the pipe velocity used for surge / swab.
Parameters (parameters)
Model parameters (SI). Defaults are order-of-magnitude placeholders; friction and damping are meant to be calibrated against field data.
- class DrillPyze.parameters.FrictionParameters(mu_static_cased=0.3, mu_kinetic_cased=0.2, mu_static_open=0.35, mu_kinetic_open=0.25, omega_c=1.0, v_c=0.01, along_string_coupling=True, axial_static_contrast=0.0, weakening='step')[source]
Bases:
objectAlong-string Coulomb friction (static/kinetic, cased/open hole).
- Parameters:
mu_static_cased (float)
mu_kinetic_cased (float)
mu_static_open (float)
mu_kinetic_open (float)
omega_c (float)
v_c (float)
along_string_coupling (bool)
axial_static_contrast (float)
weakening (str)
- mu_static_cased: float = 0.3
- mu_kinetic_cased: float = 0.2
- mu_static_open: float = 0.35
- mu_kinetic_open: float = 0.25
- omega_c: float = 1.0
- v_c: float = 0.01
- along_string_coupling: bool = True
- axial_static_contrast: float = 0.0
- weakening: str = 'step'
- class DrillPyze.parameters.DampingParameters(k_t=0.0, k_a=0.0, fluid=True, loss_factor=0.01, reference_frequency_axial=None, reference_frequency_torsional=None, high_pass_fraction=0.25, yield_drag='pumps_off', max_frequency=10.0)[source]
Bases:
objectDistributed damping (docs/derivation/README.md, sec. 5.6).
- Fluid (F1, from the mud and the string/hole geometry, no free parameter):
steady annular Couette drag on the full velocity, plus Stokes-layer drag sqrt(rho mu omega_ref / 2) on the inner and outer walls acting on the oscillatory part of the velocity (high-passed below
high_pass_fraction * omega_ref). omega_ref defaults to the first (quarter-wave) mode of the string, axial and torsional separately.- Fluid (F2): Bingham yield-stress drag tau_y * pi * OD per length, added to the
Coulomb wall friction; applied per
yield_drag.- Material (M1): Rayleigh damping zeta(f) = alpha/(2 omega) + beta omega/2 fitted so
zeta = loss_factor/2 at f_ref and at max_frequency (and below it in between); beta is Kelvin-Voigt strain-rate damping sigma = E (eps + beta deps/dt), alpha acts on the oscillatory velocity.
- Calibration: k_t, k_a are additional mass-proportional rates (1/s) on the
full velocity (the original lumped model), default 0.
Validity: the fluid terms are evaluated at a single reference frequency, so modes above it are under-damped by sqrt(f / f_ref); together with the numerical dissipation of the first-order scheme this limits the model to vibrations below
max_frequency(10 Hz).- Parameters:
k_t (float)
k_a (float)
fluid (bool)
loss_factor (float)
reference_frequency_axial (float)
reference_frequency_torsional (float)
high_pass_fraction (float)
yield_drag (str)
max_frequency (float)
- k_t: float = 0.0
- k_a: float = 0.0
- fluid: bool = True
- loss_factor: float = 0.01
- reference_frequency_axial: float = None
- reference_frequency_torsional: float = None
- high_pass_fraction: float = 0.25
- yield_drag: str = 'pumps_off'
- max_frequency: float = 10.0
- class DrillPyze.parameters.BitParameters(model='coulomb', mu_static=0.6, mu_kinetic=0.4, drilling_strength=50000000.0, zeta=0.8, contact_wob=0.0, blades=5, radius=None, strength_source='constant', cutting_efficiency=1.0, nozzle_area=0.00035628, discharge_coefficient=0.95)[source]
Bases:
objectBit-rock interaction: the axial-torsional coupling point at the bit. Three reduced models (see docs/derivation/bit-models.md); D = hole diameter, a = D/2, omega = bit speed, d = depth of cut per revolution.
coulomb– friction-dominated (worn bit / contact regime); 3 parameters:TOB = mu_kinetic * WOB * D/3 sliding; |TOB| <= mu_static * WOB * D/3 sticking ROP = omega * WOB / (2 pi a S)
cutting– Detournay & Defourny (1992), quasi-static; 3 parameters:WOB = W_f + S a d (contact threshold + cutting) TOB = WOB a / (2 zeta) (rate independent, no weakening) ROP = omega * (WOB - W_f) / (2 pi a S)
regenerative– cutting with the depth of cut set by the hole-bottom profile left by the previous blade (Richard, Germay & Detournay 2007); 2 rock parameters + the blade count:WOB = S a sum_j d_j, TOB = WOB a / (2 zeta)
S = zeta * epsilon is the drilling strength (Pa); epsilon the intrinsic specific energy; zeta the ratio of normal to tangential cutting force.
- Parameters:
model (str)
mu_static (float)
mu_kinetic (float)
drilling_strength (float)
zeta (float)
contact_wob (float)
blades (int)
radius (float)
strength_source (str)
cutting_efficiency (float)
nozzle_area (float)
discharge_coefficient (float)
- model: str = 'coulomb'
- mu_static: float = 0.6
- mu_kinetic: float = 0.4
- drilling_strength: float = 50000000.0
- zeta: float = 0.8
- contact_wob: float = 0.0
- blades: int = 5
- radius: float = None
- strength_source: str = 'constant'
- cutting_efficiency: float = 1.0
- nozzle_area: float = 0.00035628
- discharge_coefficient: float = 0.95
- class DrillPyze.parameters.TopDriveParameters(inertia=2000.0, max_torque=0.0)[source]
Bases:
objectTop-drive inertia and optional torque limit.
- Parameters:
inertia (float)
max_torque (float)
- inertia: float = 2000.0
- max_torque: float = 0.0
- class DrillPyze.parameters.RampParameters(omega_sp=0.0, omega_td=1.0, motor_torque=0.0, v_block=2.0, wob_sp=0.0, flow_rate=3.0, inlet_temperature=3.0)[source]
Bases:
objectRamp times (s) for set-point changes on inputs that have no controller. Such a set point approaches a new value linearly from its current value over its ramp time (0 = instant); ramps are evaluated inside the time stepping, so pausing and resuming stays exact.
Set points that feed a controller – the top-drive speed set point (
omega_sp, PI / SoftTorque / ZTorque) and the autodriller WOB set point (wob_sp) – are not ramped by default: the controller shapes the response. Their entries exist only for studies of set-point profiling.- Parameters:
omega_sp (float)
omega_td (float)
motor_torque (float)
v_block (float)
wob_sp (float)
flow_rate (float)
inlet_temperature (float)
- omega_sp: float = 0.0
- omega_td: float = 1.0
- motor_torque: float = 0.0
- v_block: float = 2.0
- wob_sp: float = 0.0
- flow_rate: float = 3.0
- inlet_temperature: float = 3.0
- class DrillPyze.parameters.HydraulicsParameters(enabled=True, dx=30.0, cut_factor=1.5, cfl=0.8, iterations=2, back_pressure=0.0, surface_loss_coefficient=0.0, surface_loss_exponent=1.8, clinging_constant=0.45)[source]
Bases:
objectCirculating-system hydraulics (DrillPyze.hydraulics; docs/derivation/hydraulics.md). Steady losses per Shor, Introduction to Drilling Engineering, ch. 7; transients from the single-phase drift-flux model of Wang et al. (2023, SPE-214836-MS).
- Parameters:
enabled (bool)
dx (float)
cut_factor (float)
cfl (float)
iterations (int)
back_pressure (float)
surface_loss_coefficient (float)
surface_loss_exponent (float)
clinging_constant (float)
- enabled: bool = True
- dx: float = 30.0
- cut_factor: float = 1.5
- cfl: float = 0.8
- iterations: int = 2
- back_pressure: float = 0.0
- surface_loss_coefficient: float = 0.0
- surface_loss_exponent: float = 1.8
- clinging_constant: float = 0.45
- class DrillPyze.parameters.ControllerParameters(kp=0.0, ki=0.0, impedance=0.0, t_hp=10.0, t_lp=0.005, t_en=0.001, name='unset')[source]
Bases:
objectTop-drive speed controller (Aarsnes et al. 2018, Fig. 4). Use the factories in
DrillPyze.controllersrather than setting these by hand.- Parameters:
kp (float)
ki (float)
impedance (float)
t_hp (float)
t_lp (float)
t_en (float)
name (str)
- kp: float = 0.0
- ki: float = 0.0
- impedance: float = 0.0
- t_hp: float = 10.0
- t_lp: float = 0.005
- t_en: float = 0.001
- name: str = 'unset'
- class DrillPyze.parameters.DrawworksParameters(block_acceleration=0.0)[source]
Bases:
objectDrawworks limits for prescribed block velocity.
- Parameters:
block_acceleration (float)
- block_acceleration: float = 0.0
- class DrillPyze.parameters.AutodrillerParameters(kp=1e-07, ki=1e-08, v_max=0.016666666666666666)[source]
Bases:
objectPI autodriller on surface WOB: gains and maximum block speed.
- Parameters:
kp (float)
ki (float)
v_max (float)
- kp: float = 1e-07
- ki: float = 1e-08
- v_max: float = 0.016666666666666666
- class DrillPyze.parameters.ModelParameters(friction=<factory>, damping=<factory>, bit=<factory>, top_drive=<factory>, controller=None, autodriller=<factory>, drawworks=<factory>, ramps=<factory>, hydraulics=<factory>, thermal=<factory>, thermal_update_period=2.0, cfl=0.95)[source]
Bases:
objectAll model parameters: friction, damping, bit, top drive, controller, autodriller, drawworks, ramps, hydraulics, thermal and the CFL number.
- Parameters:
friction (FrictionParameters)
damping (DampingParameters)
bit (BitParameters)
top_drive (TopDriveParameters)
controller (ControllerParameters)
autodriller (AutodrillerParameters)
drawworks (DrawworksParameters)
ramps (RampParameters)
hydraulics (HydraulicsParameters)
thermal (ThermalParameters)
thermal_update_period (float)
cfl (float)
- friction: FrictionParameters
- damping: DampingParameters
- bit: BitParameters
- top_drive: TopDriveParameters
- controller: ControllerParameters = None
- autodriller: AutodrillerParameters
- drawworks: DrawworksParameters
- ramps: RampParameters
- hydraulics: HydraulicsParameters
- thermal: ThermalParameters
- thermal_update_period: float = 2.0
- cfl: float = 0.95
Top-drive controllers (controllers)
Top-drive controller factories (Aarsnes, di Meglio & Shor 2018, Sec. 3).
All three industrial controllers share one block diagram: a PI speed loop,
optionally with impedance feedback of band-pass filtered pipe torque. The
factories compute gains from the drill-pipe characteristic impedance
zeta_p = J_p sqrt(G rho) and the top-drive inertia.
Controllers that do not fit this structure can be written in Python and run in
the simulator’s external-torque mode (see Simulation.step()).
- DrillPyze.controllers.pipe_impedance(grid)[source]
Torsional characteristic impedance of the top cell, zeta_p = J sqrt(G rho) (N m s).
- DrillPyze.controllers.stiff(zeta_p, inertia)[source]
Industry-standard stiff PI: Kp = 100 zeta_p, Ki = 5 I_TD (eq. 8).
- DrillPyze.controllers.soft_torque(zeta_p, inertia, f_c)[source]
SoftTorque/SoftSpeed: Kp = 4 zeta_p, Ki = (2 pi f_c)^2 I_TD (eqs. 11-12), where
f_c(Hz) is the frequency at which the reflection coefficient is minimised, normally the first torsional mode of the string.
- DrillPyze.controllers.z_torque(zeta_p, inertia, t_hp=10.0, t_lp=0.001, t_en=0.001, kp=None, ki=None)[source]
ZTorque: a stiff inner speed loop whose reference is corrected by the band-pass filtered pipe torque, Z = 1/zeta_p (eqs. 14-15), so the top drive behaves like a matched impedance. The inner loop must be stiff for the top drive to actually follow the corrected reference; pairing the impedance feedback with soft PI gains is unstable. Defaults follow the paper (1 ms speed and low-pass filters, 10 s high-pass). Convergence to the set point is governed by
t_hp.
- DrillPyze.controllers.custom(kp, ki, impedance=0.0, t_hp=10.0, t_lp=0.005, t_en=0.001, name='custom')[source]
Any controller with the same block structure.
Time-step kernel (kernel)
Numba time-stepping kernel for the coupled axial-torsional drillstring model.
See docs/derivation/README.md for the equations. The kernel is written over plain
arrays so it compiles to tight machine code; DrillPyze.Simulation
owns the arrays and provides the user-facing API.
- DrillPyze.kernel.advance(nsteps, sc, pf, pi, h, Kt, mt, Zt, Ka, ma, Za, rc, wb_len, kx, ky, kz, zx, zy, zz, mus, muk, qs_c, fn0, w, tau, v, qd, ramps, rec, rec_idx, rec_every, rec_phase, wf, tf, vf, qf, surf, k0t, k0a, k1t, k1a, wbar, vbar, kvt, kva, fy)[source]
Advance the model
nstepstime steps. State arrays are updated in place.Damping: k0* (1/s) act on the full velocity (Couette + calibration), k1* (1/s) on the oscillatory part w - wbar (Stokes layer; wbar is a per-cell low-pass state), kv* (N s/m resp. N m s) are Kelvin-Voigt face conductances (n+1, zero at the ends), fy (N/m) the yield-stress drag. Every
rec_everysteps a row is written intorecstarting atrec_idx; returns (new rec_idx, new rec_phase).
Well path (survey)
Wellbore survey with minimum-curvature geometry.
All quantities are SI: measured depth in m, angles in radians internally.
Inclination and azimuth may be supplied in degrees with degrees=True
(the default, since surveys are almost always reported in degrees).
- class DrillPyze.survey.Survey(md, inc, azi, degrees=True)[source]
Bases:
objectA directional survey with minimum-curvature interpolation.
- Parameters:
md (array_like) – Measured depth of each station (m), strictly increasing.
inc (array_like) – Inclination and azimuth of each station.
azi (array_like) – Inclination and azimuth of each station.
degrees (bool) – If True (default)
incandaziare in degrees.
- classmethod from_dataframe(df, md='md', inc='inc', azi='azi', md_scale=1.0, degrees=True)[source]
Build a survey from a DataFrame.
md_scaleconverts the depth column to metres (e.g.units.FTfor a survey in feet).
- classmethod from_file(path, md='md', inc='inc', azi='azi', md_scale=1.0, degrees=True, **read_kwargs)[source]
Load a survey from a .csv or .xlsx file.
- property td
Deepest surveyed measured depth (m).
- tangent(md)[source]
Unit tangent vectors (north, east, down) at arbitrary measured depths, interpolated along the minimum-curvature arcs. Depths beyond the last station are extrapolated tangentially.
Wellbore and fluid (wellbore)
Wellbore (survey + casing/open-hole geometry) and drilling fluid. SI units.
- class DrillPyze.wellbore.Fluid(density=1000.0, plastic_viscosity=None, yield_point=None, viscosity=0.02, heat_capacity=3750.0, thermal_conductivity=0.75, thermal_expansion=0.0001, sound_speed=1500.0, reference_temperature=20.0)[source]
Bases:
objectDrilling fluid.
- Mechanical:
density mud density at the reference temperature and surface (kg/m^3) plastic_viscosity Bingham PV (Pa s); not used by the mechanics yet yield_point Bingham YP (Pa); not used yet
- Thermal and hydraulic (Wang et al. 2023, SPE-214836-MS, Table 2 defaults):
viscosity effective viscosity for hydraulics and heat transfer (Pa s) heat_capacity J/(kg K) thermal_conductivity W/(m K) thermal_expansion volumetric expansion coefficient (1/K), eq. 2 sound_speed m/s, sets compressibility in eq. 2 reference_temperature C, temperature at which
densityapplies
- Parameters:
density (float)
plastic_viscosity (float)
yield_point (float)
viscosity (float)
heat_capacity (float)
thermal_conductivity (float)
thermal_expansion (float)
sound_speed (float)
reference_temperature (float)
- density: float = 1000.0
- plastic_viscosity: float = None
- yield_point: float = None
- viscosity: float = 0.02
- heat_capacity: float = 3750.0
- thermal_conductivity: float = 0.75
- thermal_expansion: float = 0.0001
- sound_speed: float = 1500.0
- reference_temperature: float = 20.0
- class DrillPyze.wellbore.Wellbore(survey, casing_shoe, hole_diameter, casing_id=None)[source]
Bases:
objectA wellbore: survey, casing shoe depth and hole sizes.
- Parameters:
survey (Survey)
casing_shoe (float) – Measured depth of the deepest casing shoe (m). Friction above the shoe uses the cased-hole friction factors.
hole_diameter (float) – Open-hole (bit) diameter (m).
casing_id (float, optional) – Inner diameter of the casing (m); informational.
Drillstring (drillstring)
Drillstring description and spatial discretisation.
Components are listed from the bit upward (the usual BHA-report order). The top component (normally drill pipe) is stretched or shortened so that the string reaches the requested bit depth. All values are SI.
- class DrillPyze.drillstring.Component(name, length, od, id, linear_mass=None, contact_od=None, E=207000000000.0, G=79300000000.0, density=7850.0)[source]
Bases:
objectOne drillstring component.
- Parameters:
name (str) – Description, e.g. ‘Bit’, ‘Motor’, ‘DC’, ‘HWDP’, ‘DP’.
length (float) – Length (m).
od (float) – Body outer and inner diameter (m).
id (float) – Body outer and inner diameter (m).
linear_mass (float, optional) – Mass per length including tool joints (kg/m). If omitted, the mass of a plain steel tube is used.
contact_od (float, optional) – Diameter that contacts the borehole (tool joint or stabiliser OD, m). Defaults to
od.E (float) – Young’s and shear modulus (Pa). Steel by default.
G (float) – Young’s and shear modulus (Pa). Steel by default.
density (float) – Material density (kg/m^3), used when
linear_massis not given.
- name: str
- length: float
- od: float
- id: float
- linear_mass: float = None
- contact_od: float = None
- E: float = 207000000000.0
- G: float = 79300000000.0
- density: float = 7850.0
- property area
Steel cross-section (m^2).
- property polar_moment
Polar second moment of area (m^4).
- property mass_per_length
linear_mass if given, else steel density x area.
- Type:
Mass per length (kg/m)
- property effective_density
Density that gives the stated mass per length over the body area.
- class DrillPyze.drillstring.Grid(x_top, dx, od, id, r_contact, A, J, rho, E, G, component)[source]
Bases:
objectCell-wise properties of a discretised drillstring (index 0 at surface).
- Parameters:
x_top (ndarray)
dx (ndarray)
od (ndarray)
id (ndarray)
r_contact (ndarray)
A (ndarray)
J (ndarray)
rho (ndarray)
E (ndarray)
G (ndarray)
component (ndarray)
- x_top: ndarray
- dx: ndarray
- od: ndarray
- id: ndarray
- r_contact: ndarray
- A: ndarray
- J: ndarray
- rho: ndarray
- E: ndarray
- G: ndarray
- component: ndarray
- property n
Number of cells.
- property x
MD of cell centres (m).
- property x_bottom
Measured depth of the bottom of each cell along the string (m).
- property c_axial
Axial wave speed per cell, sqrt(E/rho) (m/s).
- property c_torsional
Torsional wave speed per cell, sqrt(G/rho) (m/s).
- class DrillPyze.drillstring.Drillstring(components, name='Drillstring')[source]
Bases:
objectA drillstring built from components listed bit-first.
The last component in the list (top of the string) is the one that is lengthened to reach surface; normally drill pipe.
- classmethod from_dataframe(df, name='Drillstring', length_scale=1.0, diameter_scale=1.0, mass_scale=1.0, bit_first=True)[source]
Build from a table with columns
name, length, od, idand optionallinear_mass, contact_od. The scale arguments convert the table’s units to SI (e.g.length_scale=units.FT, diameter_scale=units.IN, mass_scale=units.LB_FT).
- property bha_length
Length of all components except the top (filler) component.
Cell geometry (geometry)
Per-cell wellbore geometry used by both the torque & drag model and the dynamic simulator, so the two compute identical normal forces.
The soft-string normal force per unit length on a cell is
F_N = | T * dt/ds + w_b * z_perp |
where t is the unit tangent, T the effective tension, w_b the
buoyed weight per length and z_perp the component of the downward unit
vector perpendicular to the pipe. This vector form is equivalent to the
Johancsik et al. (1984) expression and is valid for any change in azimuth
(including crossing north) without special handling.
- class DrillPyze.geometry.CellGeometry(t_z, kappa, z_perp, inc, azi, tvd)[source]
Bases:
objectPer-cell well-path geometry seen by the string at its present position.
- Parameters:
t_z (ndarray)
kappa (ndarray)
z_perp (ndarray)
inc (ndarray)
azi (ndarray)
tvd (ndarray)
- t_z: ndarray
- kappa: ndarray
- z_perp: ndarray
- inc: ndarray
- azi: ndarray
- tvd: ndarray
- DrillPyze.geometry.cell_geometry(survey, grid)[source]
Compute
CellGeometryfor a discretised string in a survey.
Steady torque and drag (statics)
Steady-state soft-string torque and drag (SI units).
Friction on each element opposes the sliding velocity of the pipe surface,
which has an axial component v (positive downhole) and a tangential
component omega * r. Rotation therefore reduces drag, the classic
velocity-split model. Normal force uses the vector soft-string relation in
DrillPyze.geometry and is updated with the local tension while
integrating from the bit up (Johancsik et al. 1984; Sheppard et al. 1987).
Sign conventions
tensionis effective tension, positive in tension. At the bit it is-WOB.torqueis the torque transmitted downward, positive in the rotation direction. At the bit it isTOB.v > 0is moving downhole (slack-off / RIH),v < 0is pick-up.
- class DrillPyze.statics.TorqueDragResult(md, tension, torque, normal_force)[source]
Bases:
objectSteady torque-and-drag profiles along the string.
- Parameters:
md (ndarray)
tension (ndarray)
torque (ndarray)
normal_force (ndarray)
- md: ndarray
- tension: ndarray
- torque: ndarray
- normal_force: ndarray
- property hookload
Effective tension at surface (N), excluding block weight.
- property surface_torque
Torque at the top of the string (N m).
- DrillPyze.statics.friction_profile(wellbore, grid, mu_cased, mu_open)[source]
Per-cell friction factor:
mu_casedabove the shoe,mu_openbelow.
- DrillPyze.statics.torque_drag(wellbore, grid, fluid_density, mu_cased, mu_open=None, v=0.0, omega=0.0, wob=0.0, tob=0.0, geometry=None, normal_force=None)[source]
Soft-string torque and drag for one operating state.
- Parameters:
wellbore (Wellbore)
grid (drillstring.Grid) – Discretised string (from
Drillstring.discretize).fluid_density (float) – Mud density (kg/m^3) for buoyancy.
mu_cased (float) – Friction factors inside casing and in open hole.
mu_opendefaults tomu_cased.mu_open (float) – Friction factors inside casing and in open hole.
mu_opendefaults tomu_cased.v (float) – Axial pipe velocity (m/s), positive downhole. Only its direction relative to
omega * rmatters.omega (float) – Rotary speed (rad/s).
wob (float) – Weight on bit (N) and torque on bit (N m).
tob (float) – Weight on bit (N) and torque on bit (N m).
normal_force (array, optional) – Fixed normal force per length for each cell (N/m). By default it is computed from the local tension (soft string).
states (Common)
-------------
bottom (rotating off)
slack-off (
v>0, omega=0; drilling:omega>0, v=ROP, wob, tob.)
Hydraulics (hydraulics)
Borehole hydraulics (SI units).
- Steady state
Newtonian and Bingham-plastic pressure losses in pipe and annular flow, bit nozzle loss, standpipe pressure, bottomhole pressure and ECD, as in Shor, Introduction to Drilling Engineering, ch. 7 (Borehole Hydraulics):
* apparent viscosity: pipe mu_a = PV + tau_y D / (6 v) annulus mu_a = PV + tau_y (D2 - D1) / (8 v) * Reynolds number: pipe Re = rho v D / mu_a annulus Re = rho v 0.816 (D2 - D1) / mu_a laminar below 2100, turbulent (transition treated as turbulent) above * laminar: pipe dp/dL = 32 PV v / D^2 + 16 tau_y / (3 D) annulus dp/dL = 48 PV v / h^2 + 6 tau_y / h, h = D2 - D1 (slot flow, 12 PV v / g^2 + 3 tau_y / g with the gap g = h / 2) * turbulent: Fanning, Blasius f = 0.0791 Re^-0.25 with Re on PV, dp/dL = 2 f rho v^2 / D_e, D_e = D (pipe), 0.816 h (annulus) * bit: dp = rho Q^2 / (2 C_d^2 A_n^2) * SPP = dp_surface + dp_string + dp_bit + dp_annulus; BHP = p_hydrostatic + dp_annulus
(These are the chapter’s field-unit equations written in SI.) A Newtonian fluid is the special case tau_y = 0, PV = mu.
- Transient
WellboreHydraulics– the single-phase limit of the drift-flux model of Wang, Khaled, Luu, Ashok & van Oort (2023, SPE-214836-MS; after Evje & Fjelde 2002): mass and momentum along the drillstring and annulus with rho(T, p) of their eq. 2, a volume-rate inlet, a constant-pressure outlet, fixed cells with volume-averaged cross sections, and the bit nozzles linking the two flow paths. See docs/derivation/hydraulics.md.
- DrillPyze.hydraulics.fluid_velocity(Q, Do, Di=None)[source]
Mean velocity (m/s) for flow rate
Q(m^3/s).
- DrillPyze.hydraulics.hydraulic_diameter(Do, Di=None)[source]
Hydraulic diameter: Do for a pipe, Do - Di for an annulus.
- DrillPyze.hydraulics.reynolds_number(rho, v, mu, Do, Di=None)[source]
Newtonian Reynolds number on the hydraulic diameter.
- DrillPyze.hydraulics.friction_factor(Re)[source]
Fanning friction factor (16/Re laminar, Blasius turbulent).
- DrillPyze.hydraulics.frictional_pressure_drop(rho, Q, mu, L, Do, Di=None)[source]
Frictional pressure drop (Pa) over
L(m) for a Newtonian fluid (chapter 7 forms).
- DrillPyze.hydraulics.rheology(fluid)[source]
(PV, tau_y) of a
Fluid: Bingham if a yield point is given.
- DrillPyze.hydraulics.gradient(u, rho, pv, ty, d_out, d_in)[source]
Frictional pressure gradient (Pa/m), signed with the velocity
u(m/s).
- DrillPyze.hydraulics.section(Q, rho, pv, ty, length, d_out, d_in=0.0)[source]
One textbook section: velocity, apparent viscosity, Reynolds number, regime and pressure loss. Pipe if
d_inis 0, annulus otherwise.
- DrillPyze.hydraulics.nozzle_area(sizes_32nds)[source]
Total flow area (m^2) of nozzles given in 32nds of an inch.
- DrillPyze.hydraulics.bit_pressure_drop(Q, rho, tfa, cd=0.95)[source]
Bit nozzle pressure drop (Pa): rho Q^2 / (2 C_d^2 A^2).
- DrillPyze.hydraulics.surface_loss(Q, coefficient=0.0, exponent=1.8)[source]
Surface-equipment loss c Q^m (Pa); the chapter’s empirical form.
- DrillPyze.hydraulics.steady_state(Q, density, pv, ty, pipe, annulus, tfa, tvd, cd=0.95, surface=0.0)[source]
Textbook steady-state circulating system (constant density).
pipe list of (name, inner diameter, length) annulus list of (name, hole diameter, pipe outer diameter, length) tfa total nozzle area (m^2); tvd (m); surface loss (Pa)
Returns dict with a per-section table, bit loss, SPP, annular loss, hydrostatic pressure, BHP and ECD (kg/m^3).
- class DrillPyze.hydraulics.WellboreHydraulics(wellbore, grid, fluid, params, tfa, cd, bit_depth, hole_depth, bit_depth0)[source]
Bases:
objectTransient single-phase drift-flux hydraulics of the circulating system.
Two flow paths on fixed cells (cell edges fixed in measured depth): the drillstring bore from surface to the bit, and the annulus (plus rat hole) from surface to the hole bottom. Cross sections are volume-averaged over the string occupying each cell (Wang et al. 2023, Fig. 1); the bottom annulus cell grows with the hole and the bottom drillstring cell follows the bit (grow-cut-grow, Fig. 2).
State: mass per cell (both paths) and mass flux per face. Pressure from rho(T, p) of Wang et al. eq. 2: p = c^2 (m/V - rho_T). Inlet: pump volume rate. Outlet: flowline at
back_pressure. The bit nozzles are a face between the bottom drillstring cell and the annulus cell at the bit.advance(t0, t1, ...)integrates with an explicit acoustic step on the pressures and a backward-Euler, Picard-iterated step on the face fluxes (friction, nozzle loss and Bingham yield stress implicit).- set_temperatures(md_ds, t_ds, md_ann, t_ann)[source]
Mud temperatures (C) from the thermal model, interpolated to the cells.
- set_steady(Q)[source]
Exact discrete steady state of the transient scheme at pump rate
Q(m^3/s) with the pipe at rest: constant mass flux on every face, and on each face drive = friction (fixed-point on the face densities).
Wellbore temperature (thermal)
Transient wellbore temperature while drilling, after the modified drift-flux model of Wang, Khaled, Luu, Ashok & van Oort (2023), “Downhole Temperature Estimation of a Growing High-Temperature Wellbore Using a Modified Drift Flux Modeling Approach”, SPE-214836-MS, doi:10.2118/214836-MS.
Implemented here in its single-phase (liquid mud) form:
drillstring and annulus fluid energy balances on a common axial grid, upwind in the flow direction (paper eqs. 3-5, 13);
radial heat flow drillstring <-> annulus and annulus <-> formation through series conduction/convection resistances (eqs. 6-9; Nusselt number from Dittus-Boelter for turbulent flow, 3.66 for laminar flow);
the formation as radial conduction cells per axial cell with the undisturbed geothermal temperature in the far field (Khaled et al. 2023c);
a growing bottom cell, grown at the ROP and cut in two when it reaches a threshold (the “grow-cut-grow” strategy, Fig. 2), with the cuttings entering at the formation temperature (eqs. 14-20) and the bottom formation cells relaxed toward the undisturbed temperature as the hole deepens (eq. 10);
mud density rho(T, p) (eq. 2) integrated up the annulus with the frictional pressure loss to give the bottomhole pressure and ECD.
Simplifications relative to the paper, all consistent with its assumptions 1-3: single liquid phase (gas volume fraction zero), velocity from the pump rate (ROP << mud velocity), axial conduction in the fluid neglected, transient heat storage in the drillstring steel neglected, cuttings carry their heat into the mud at the bottom cell. Moving geometry discontinuities are handled by volume-averaging the string geometry over each cell at every update (Fig. 1); the associated ROP-scaled area-change terms of eqs. 11-13 are O(ROP/v) and omitted.
Units: SI, temperatures in deg C.
- class DrillPyze.thermal.ThermalParameters(enabled=True, dx=30.0, cut_factor=1.5, n_radial=12, far_field=5.0, steel_conductivity=45.0, casing_thickness=0.012, flow_rate=0.0347, inlet_temperature=30.0, max_dt=2.0, gs_iterations=3)[source]
Bases:
objectWellbore temperature model settings: grid, radial formation cells, steel and casing properties, initial pump rate and inlet temperature, substep and iterations.
- Parameters:
enabled (bool)
dx (float)
cut_factor (float)
n_radial (int)
far_field (float)
steel_conductivity (float)
casing_thickness (float)
flow_rate (float)
inlet_temperature (float)
max_dt (float)
gs_iterations (int)
- enabled: bool = True
- dx: float = 30.0
- cut_factor: float = 1.5
- n_radial: int = 12
- far_field: float = 5.0
- steel_conductivity: float = 45.0
- casing_thickness: float = 0.012
- flow_rate: float = 0.0347
- inlet_temperature: float = 30.0
- max_dt: float = 2.0
- gs_iterations: int = 3
- class DrillPyze.thermal.WellboreThermal(wellbore, drillstring, fluid, formation, params, bit_depth, hole_depth, initial='geothermal')[source]
Bases:
objectWellbore temperature model coupled to a
Simulation.Call
advance()with the elapsed time, pump rate, inlet temperature, bit and hole depth and ROP. The grid follows the hole as it is drilled.- Parameters:
params (ThermalParameters)
- advance(duration, flow_rate=None, inlet_temperature=None, bit_depth=None, hole_depth=None, rop=0.0)[source]
Advance the temperature field by
durationseconds.
- state()[source]
Temperatures at the bit, outlet and inlet, rock temperature, bottomhole pressure, ECD and pump rate.
Formation and rock strength (formation)
Formation description and rock strength at the bit.
Rock strength enters the bit models through the drilling strength S = zeta * epsilon, with the intrinsic specific energy taken as the confined compressive strength at the bit divided by a cutting efficiency eta:
epsilon = CCS_eff / eta
CCS_eff combines three effects (see docs/derivation/rock-strength-and-temperature.md):
P1 Confinement by the overbalance, Mohr-Coulomb
CCS = UCS + dp * (1 + sin phi) / (1 - sin phi)
with dp = p_bh - p_p for permeable rock, and for low-permeability /
low-porosity rock the undrained ("Skempton") pore pressure
p_p* = p_p - B (sigma_v - p_bh) / 3
blended by effective porosity (Caicedo, Calhoun & Ewy 2005; US 7,412,331
and US 7,555,414).
T1 Thermal weakening of the rock
UCS(T) = UCS_0 [1 - beta max(T - T*, 0)]
fitted to granite data of Xu et al. (2019): T* = 193 C, beta = 1.41e-3 /K.
T2 Cooling-induced thermal stress at the hole bottom
sigma_th = alpha E (T_rock - T_mud) / (1 - nu)
CCS_eff = CCS - kappa sigma_th min(1, delta / d_b)
where delta = sqrt(pi D_th t_pass) is the thermal skin cooled between
blade passes and d_b the depth of cut per blade.
Temperatures are in deg C, pressures in Pa, depths in m.
- class DrillPyze.formation.FormationLayer(top_md, ucs=110000000.0, friction_angle=36.0, porosity=0.005, name='')[source]
Bases:
objectA formation interval starting at
top_md(m MD) and extending to the next layer.- Parameters:
top_md (float)
ucs (float)
friction_angle (float)
porosity (float)
name (str)
- top_md: float
- ucs: float = 110000000.0
- friction_angle: float = 36.0
- porosity: float = 0.005
- name: str = ''
- class DrillPyze.formation.Formation(layers=<factory>, pore_pressure_gradient=9790.0, overburden_gradient=25000.0, skempton_b=1.0, porosity_low=0.05, porosity_high=0.2, surface_temperature=40.0, geothermal_gradient=0.0691, rock_density=2800.0, rock_heat_capacity=930.0, rock_conductivity=2.31, thermal_expansion=6e-06, youngs_modulus=55000000000.0, poisson_ratio=0.26, weakening_threshold=193.0, weakening_rate=0.00141, thermal_stress_efficiency=0.5, strength_floor=0.1)[source]
Bases:
objectFormation, pore-pressure and geothermal description.
- Defaults are for the Utah FORGE granitoid:
UCS 91-126 MPa (Ye et al. 2022, ARMA-2022-0272), friction angle 36 deg (Finnila & Podgorney 2020), matrix porosity < 0.5 %, E ~ 55 GPa, nu ~ 0.26, alpha = 6e-6 /K (Podgorney et al. 2021; compiled in the Utah FORGE decade review, Processes 2026, 14, 512); geothermal 40 C surface and 69.1 C/km, rock density 2800 kg/m3, heat capacity 930 J/kg K, conductivity 2.31 W/m K (Wang et al. 2023, SPE-214836-MS, Table 2).
- Parameters:
layers (List[FormationLayer])
pore_pressure_gradient (float)
overburden_gradient (float)
skempton_b (float)
porosity_low (float)
porosity_high (float)
surface_temperature (float)
geothermal_gradient (float)
rock_density (float)
rock_heat_capacity (float)
rock_conductivity (float)
thermal_expansion (float)
youngs_modulus (float)
poisson_ratio (float)
weakening_threshold (float)
weakening_rate (float)
thermal_stress_efficiency (float)
strength_floor (float)
- layers: List[FormationLayer]
- pore_pressure_gradient: float = 9790.0
- overburden_gradient: float = 25000.0
- skempton_b: float = 1.0
- porosity_low: float = 0.05
- porosity_high: float = 0.2
- surface_temperature: float = 40.0
- geothermal_gradient: float = 0.0691
- rock_density: float = 2800.0
- rock_heat_capacity: float = 930.0
- rock_conductivity: float = 2.31
- thermal_expansion: float = 6e-06
- youngs_modulus: float = 55000000000.0
- poisson_ratio: float = 0.26
- weakening_threshold: float = 193.0
- weakening_rate: float = 0.00141
- thermal_stress_efficiency: float = 0.5
- strength_floor: float = 0.1
- property thermal_diffusivity
Rock thermal diffusivity k / (rho c) (m^2/s).
- strength(md, tvd, p_bh, t_mud=None, rop=0.0, omega=0.0, blades=5)[source]
Rock strength at the bit.
- Parameters:
md (float) – Hole depth (m MD) and its TVD (m).
tvd (float) – Hole depth (m MD) and its TVD (m).
p_bh (float) – Bottomhole pressure (Pa), e.g. from the circulating thermal/hydraulic model.
t_mud (float, optional) – Mud temperature at the bit (C). None disables the thermal-stress term.
rop (float) – Penetration rate (m/s) and bit speed (rad/s), for the thermal skin ratio.
omega (float) – Penetration rate (m/s) and bit speed (rad/s), for the thermal skin ratio.
blades (int) – Number of blades (sets the time between blade passes).
- Returns:
dict with ucs0, t_rock, ucs_t, dp_drained, dp_undrained, w_drained,
ccs (P1 + T1), sigma_th, skin_ratio, ccs_eff (P1 + T1 + T2).
Units (units)
Unit conversions.
DrillPyze works in SI units internally (m, s, kg, N, rad, Pa). Field data are often in oilfield units; these helpers convert at the input/output boundary.
Simulator UI server (ui.server)
DrillPyze interactive UI server.
A small standard-library HTTP server that owns Simulation objects and
steps them on request; the browser front end (static/) edits the case,
drives the transport (play / pause / step) and animates the results.
Run with drillpyze-ui (or python -m DrillPyze.ui) and open the printed
address. API (JSON over HTTP):
GET /api/defaults default case config (Well A) POST /api/init {config} build + initialise a simulation -> session, geometry, first frame POST /api/step {session, duration, inputs} advance and return one frame GET /api/results.csv?session=… all recorded channels (SI) as CSV
- class DrillPyze.ui.server.Session(cfg)[source]
Bases:
objectOne UI simulation: the built model, its inputs and what has been sent to the browser.
- apply_inputs(inp)[source]
Translate UI inputs (display units) into Simulation.step keyword arguments.
- class DrillPyze.ui.server.Handler(request, client_address, server)[source]
Bases:
BaseHTTPRequestHandlerHTTP handler: static files and the JSON API (/api/defaults, /api/init, /api/step, /api/results.csv).
- server_version = 'DrillPyzeUI/0.1'
- DrillPyze.ui.server.make_server(host='127.0.0.1', port=8050, verbose=False)[source]
Threaded HTTP server for the UI on host:port.