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.default()[source]

The default case (currently Well A).

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 Simulation from a config dict.

DrillPyze.config.validate(cfg)[source]

Return a list of human-readable problems with a config (empty if fine).

DrillPyze.config.save(cfg, path)[source]

Write a case to a JSON file.

DrillPyze.config.load(path)[source]

Read a case from a JSON file.

DrillPyze.config.merge(base, override)[source]

Deep-merge override into a copy of base.

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:
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_true scales the Stokes part by sqrt(f/f_ref) as the physical layer would.

flow_rate_now()[source]

Current (ramped) pump rate, m^3/s.

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 duration seconds with inputs held constant. Inputs not given keep their previous values.

Top drive (choose one; the most recently given one sets the mode):

omega_sp speed set point (rad/s) for the internal controller motor_torque motor torque (N m) from an external controller omega_td prescribed top-drive speed (rad/s), e.g. measured RPM

Drawworks (choose one):

v_block block velocity (m/s, positive lowering) wob_sp WOB set point (N) for the autodriller

Circulation (hydraulics and wellbore temperature):

flow_rate pump rate (m^3/s) inlet_temperature mud 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).

latest()[source]

Latest scalar values as a dict (SI units).

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 pressure p_bh (Pa gauge), ecd (kg/m^3), pump rate q_in, return flow q_out, bit flow q_bit (m^3/s), bit pressure drop dp_bit, surface loss and the pipe velocity used for surge / swab.

slow_results()[source]

Channels from the slow models (one row per thermal update): mud temperatures (C), bottomhole pressure (Pa), ECD (kg/m3), rock temperature, UCS(T), CCS, effective CCS, thermal stress (Pa), drilling strength S (Pa), average ROP (m/s) and bit speed (rad/s).

results()[source]

All recorded scalar channels as a DataFrame (SI units).

profiles()[source]

Current along-string state as a DataFrame (one row per cell).

clear_results()[source]

Discard recorded data (the state is kept).

snapshot()[source]

A deep copy of the full simulation (for ensembles or rewinding).

info()[source]

Grid and numerics summary: cells, time step, cell sizes, string length, pipe impedance, controller name and torsional CFL number.

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: object

Along-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: object

Distributed 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: object

Bit-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: object

Top-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: object

Ramp 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
classmethod instant()[source]

All ramps off (inputs change in one time step).

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: object

Circulating-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: object

Top-drive speed controller (Aarsnes et al. 2018, Fig. 4). Use the factories in DrillPyze.controllers rather 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: object

Drawworks 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: object

PI 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: object

All 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 = None
autodriller: AutodrillerParameters
drawworks: DrawworksParameters
ramps: RampParameters
hydraulics: HydraulicsParameters
thermal: ThermalParameters
thermal_update_period: float = 2.0
cfl: float = 0.95
to_dict()[source]

Plain-dict form.

copy(**changes)[source]

Copy with some fields replaced (dataclasses.replace).

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.

DrillPyze.controllers.reflection_coefficient(c, zeta_p, inertia, freqs)[source]

Top-side torsional reflection coefficient |(C(s)+I s - zeta)/(C(s)+I s + zeta)| at frequencies freqs (Hz), ignoring the impedance-feedback path (eq. 10).

Parameters:

c (ControllerParameters)

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 nsteps time 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_every steps a row is written into rec starting at rec_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: object

A 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) inc and azi are 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_scale converts the depth column to metres (e.g. units.FT for 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.

inc_azi(md)[source]

Interpolated inclination and azimuth (radians) at measured depths.

positions(md)[source]

(north, east, tvd) in metres at measured depths, by integrating the interpolated tangent along the minimum-curvature path.

tvd_at(md)[source]

True vertical depth (m) at measured depths (numerical arc integration).

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: object

Drilling 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 density applies

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
density_at(T, p)[source]

Mud density at temperature T (C) and gauge pressure p (Pa), Wang et al. (2023) eq. 2.

class DrillPyze.wellbore.Wellbore(survey, casing_shoe, hole_diameter, casing_id=None)[source]

Bases: object

A 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.

is_cased(md)[source]

Boolean mask: True where md is inside casing.

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: object

One 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_mass is 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: object

Cell-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: object

A 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, id and optional linear_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.

discretize(bit_depth, dx=10.0)[source]

Discretise the string with the bit at bit_depth (m MD). Each component is split into equal cells no longer than dx so cell edges align with component boundaries.

Return type:

Grid

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: object

Per-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 CellGeometry for a discretised string in a survey.

DrillPyze.geometry.buoyed_weight(grid, fluid_density, g=9.80665)[source]

Buoyed weight per unit length of each cell (N/m).

DrillPyze.geometry.normal_force(T, w_b, kx, ky, kz, zx, zy, zz)[source]

Soft-string normal force per length for one cell.

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

  • tension is effective tension, positive in tension. At the bit it is -WOB.

  • torque is the torque transmitted downward, positive in the rotation direction. At the bit it is TOB.

  • v > 0 is moving downhole (slack-off / RIH), v < 0 is pick-up.

class DrillPyze.statics.TorqueDragResult(md, tension, torque, normal_force)[source]

Bases: object

Steady 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_cased above the shoe, mu_open below.

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_open defaults to mu_cased.

  • mu_open (float) – Friction factors inside casing and in open hole. mu_open defaults to mu_cased.

  • v (float) – Axial pipe velocity (m/s), positive downhole. Only its direction relative to omega * r matters.

  • 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.)

DrillPyze.statics.broomstick(wellbore, grid, fluid_density, mu_values, mode='rotating', **kwargs)[source]

Hookload or surface torque over a list of friction factors (the classic broomstick plot). mode is ‘rotating’, ‘pickup’ or ‘slackoff’. Returns an array with one value per friction factor.

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.area(Do, Di=None)[source]

Flow area (m^2) of a pipe (Di is None) or annulus.

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_in is 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: object

Transient 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_static()[source]

Hydrostatic state with no flow (exact discrete equilibrium).

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).

advance(duration, q_start, q_end, bit_depth, hole_depth)[source]

Advance by duration s; the pump rate ramps linearly from q_start to q_end (m^3/s) and the bit and hole move linearly to the given depths (string motion displaces mud: surge / swab).

state()[source]

Pump (standpipe) pressure, bottomhole pressure, ECD, flows (SI, gauge).

profiles()[source]

Pressure and density per cell of both paths (DataFrame with a path column).

mass()[source]

Total mud mass in the well (kg), for balance checks.

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: object

Wellbore 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: object

Wellbore 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 duration seconds.

state()[source]

Temperatures at the bit, outlet and inlet, rock temperature, bottomhole pressure, ECD and pump rate.

profiles()[source]

Temperature profiles per cell (DataFrame): drillstring, annulus, wall and far field.

stored_energy()[source]

Thermal energy relative to 0 C in fluid and formation (J), for balance checks.

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: object

A 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: object

Formation, 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
layer_at(md)[source]

The layer containing measured depth md (the deepest layer with top <= md).

temperature(tvd)[source]

Undisturbed formation temperature (C) at TVD (m).

pore_pressure(tvd)[source]

Hydrostatic pore pressure at true vertical depth tvd (Pa).

overburden(tvd)[source]

Overburden stress at true vertical depth tvd (Pa).

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).

to_dict()[source]

Plain-dict form (for JSON cases).

classmethod from_dict(d)[source]

Formation from its dict form; missing values take the defaults.

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.

DrillPyze.units.rpm_to_rads(rpm)[source]

Convert rev/min to rad/s.

DrillPyze.units.rads_to_rpm(w)[source]

Convert rad/s to rev/min.

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: object

One 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.

step(duration, inputs)[source]

Apply the UI inputs, advance duration seconds and return a frame.

frame(wall=0.0, duration=0.0)[source]

Everything the browser needs to draw: latest values, new trace rows (decimated), slow and hydraulics records, temperature and along-string profiles.

info()[source]

Simulation info plus the first torsional mode and controller gains.

csv()[source]

All recorded channels as CSV text.

class DrillPyze.ui.server.Handler(request, client_address, server)[source]

Bases: BaseHTTPRequestHandler

HTTP handler: static files and the JSON API (/api/defaults, /api/init, /api/step, /api/results.csv).

server_version = 'DrillPyzeUI/0.1'
log_message(fmt, *args)[source]

Log requests only when the server is verbose.

do_GET()[source]

Static files, defaults and the results CSV.

do_POST()[source]

Initialise or step a session.

DrillPyze.ui.server.make_server(host='127.0.0.1', port=8050, verbose=False)[source]

Threaded HTTP server for the UI on host:port.

DrillPyze.ui.server.warm_up()[source]

Compile the Numba kernel once so the first Initialise is quick.

DrillPyze.ui.server.main(argv=None)[source]

Command-line entry point: start the UI server and open a browser.