civilpy.geotech package

Geotechnical engineering: boring-log data models and parsers, SPT corrections, foundation capacity, lateral pile analysis, and earth pressure.

Submodules

civilpy.geotech.axial_load_transfer module

Axial pile load-transfer (t-z and q-z) curves.

The lateral-pile module (civilpy.geotech.lateral_pile) gives the p-y springs that resist horizontal pile movement; this module is the axial companion, supplying the t-z curves (mobilised side / skin friction per unit length versus axial displacement) and the q-z curve (mobilised end bearing at the tip versus tip settlement). Together the three families give the full set of foundation springs a structural model needs to support a pier or an integral-abutment pile bent on soil rather than on fixed points.

The backbone shapes are the American Petroleum Institute recommendation (API RP 2A-WSD, §6.7): normalised t/t_max and Q/Q_p tables against z/D (clay) or absolute displacement (sand), linearly interpolated. The ultimate values t_max (unit skin friction times perimeter) and Q_p (tip area times unit end bearing) come from the capacity routines in civilpy.geotech.deep_foundation, so a single boring drives capacity, settlement, and the spring model consistently.

These are normalised design curves; a settlement-sensitive structure should be checked against a project-specific load-transfer analysis.

Units: displacements in inches, forces in pounds, diameters in inches (so a t-z secant modulus is lb/in per inch of pile = lb/in^2 and a spring constant is lb/in) – matching civilpy.geotech.lateral_pile. Use spring_constant_kip_per_in() when handing values to a kip-unit model.

class civilpy.geotech.axial_load_transfer.APIQZCurve(q_max: float, diameter: float = 12.0)[source]

Bases: QZCurve

API RP 2A-WSD q-z curve. q_max is the ultimate tip resistance (lb) = tip area times unit end bearing; diameter (in) sets the z/D normalisation (full mobilisation at a tip settlement of 0.10 D).

diameter: float = 12.0
q(w: float) float[source]

Mobilised tip resistance (lb) at tip settlement w (in).

q_max: float
class civilpy.geotech.axial_load_transfer.APITZCurve(t_max: float, soil: str = 'clay', diameter: float = 12.0)[source]

Bases: TZCurve

API RP 2A-WSD t-z curve.

t_max is the ultimate side resistance per unit pile length (lb/in) – the unit skin friction times the pile perimeter. soil selects the normalised backbone: "clay" uses the z/D table (so diameter in inches is required), "sand" mobilises t_max at a fixed 0.10 in.

diameter: float = 12.0
soil: str = 'clay'
t(w: float) float[source]

Mobilised skin friction per unit length (lb/in) at axial displacement w (in).

t_max: float
class civilpy.geotech.axial_load_transfer.QZCurve[source]

Bases: object

Base class for end-bearing (q-z) curves. Subclasses implement q() and expose q_max.

q(w: float) float[source]

Mobilised tip resistance (lb) at tip settlement w (in).

q_max: float
secant_modulus(w: float) float[source]

Secant tip stiffness Q/w (lb/in) at settlement w (in).

class civilpy.geotech.axial_load_transfer.TZCurve[source]

Bases: object

Base class for axial side-resistance (t-z) curves. Subclasses implement t() and expose t_max; the secant modulus follows.

secant_modulus(w: float) float[source]

Secant load-transfer modulus t/w (lb/in^2) at displacement w (in); uses a displacement floor so it stays finite at w = 0.

t(w: float) float[source]

Mobilised skin friction per unit length (lb/in) at axial displacement w (in).

t_max: float
civilpy.geotech.axial_load_transfer.axial_pile_springs(curve: TZCurve, embedded_length: float, n_nodes: int, design_disp: float) list[tuple[float, float]][source]

Discretise an embedded pile into n_nodes equally spaced axial (t-z) springs and return (depth_in, k_lb_per_in) for each.

The spring constant at a node is the t-z secant modulus at design_disp (in) times the tributary length (in) the node represents – a linearised Winkler spring suitable for a MIDAS nodal spring support. end nodes carry half the tributary length. embedded_length is in inches.

civilpy.geotech.axial_load_transfer.spring_constant_kip_per_in(force_lb_per_in_or_lb: float) float[source]

Convert a lb/in (or lb) spring constant to kip/in (or kip).

civilpy.geotech.boring module

Canonical, library-neutral data model for a subsurface boring.

A geotechnical boring log is the hub object the rest of CivilPy reads from: the same Borehole can drive scour grain-size lookups in the hydraulics library, axial capacity in the foundations modules, and soil zone moduli for CANDE. Ingestion (DIGGS XML, PDF logs, …) lives in civilpy.geotech.boring_io and produces these objects; nothing here depends on how the data was read.

Units are US customary: depths and elevations in feet, particle sizes in millimetres (the geotechnical convention for gradations), recovery in inches. Blow counts are dimensionless.

class civilpy.geotech.boring.Borehole(boring_id: str, project: str | None = None, ground_elevation_ft: float | None = None, latitude: float | None = None, longitude: float | None = None, station: str | None = None, offset_ft: float | None = None, offset_direction: str | None = None, total_depth_ft: float | None = None, water_strike_depth_ft: float | None = None, date: str | None = None, purpose: str | None = None, samples: list[Sample] = <factory>, spt: list[SPTResult] = <factory>, grading: list[GradingResult] = <factory>)[source]

Bases: object

A single subsurface boring: header location/geometry plus the depth-indexed sample, SPT, and gradation records read from a log.

boring_id: str
d50_at(depth_ft: float) float | None[source]

D50 (mm) of the gradation nearest depth_ft – the scour input.

date: str | None = None
elevation_at(depth_ft: float) float | None[source]

Ground-surface elevation minus depth_ft (None if the collar elevation is unknown).

grading: list[GradingResult]
grading_at(depth_ft: float) GradingResult | None[source]

Gradation analysis nearest depth_ft (None if none present).

ground_elevation_ft: float | None = None
latitude: float | None = None
longitude: float | None = None
n_at(depth_ft: float) int | None[source]

SPT N of the test nearest depth_ft (None if no SPT data).

offset_direction: str | None = None
offset_ft: float | None = None
project: str | None = None
purpose: str | None = None
samples: list[Sample]
spt: list[SPTResult]
spt_profile() list[tuple[float, int]][source]

(depth_ft, N) pairs sorted by depth, skipping tests whose N is undefined.

station: str | None = None
total_depth_ft: float | None = None
water_strike_depth_ft: float | None = None
class civilpy.geotech.boring.DriveIncrement(blows: 'int', penetration_in: 'float' = 6.0)[source]

Bases: object

blows: int
penetration_in: float = 6.0
class civilpy.geotech.boring.GradingPoint(particle_size_mm: float, percent_passing: float)[source]

Bases: object

One point on a particle-size distribution: percent_passing finer than particle_size_mm.

particle_size_mm: float
percent_passing: float
class civilpy.geotech.boring.GradingResult(depth_ft: float, points: tuple[GradingPoint, ...])[source]

Bases: object

A particle-size (sieve + hydrometer) analysis on a sample taken at depth_ft. points are stored sorted coarse-to-fine.

FINES_SIZE_MM = 0.075

US No. 200 sieve opening, mm (the silt/sand fines boundary).

property coefficient_of_curvature: float | None

Cc = D30^2 / (D10 * D60).

property coefficient_of_uniformity: float | None

Cu = D60 / D10.

property d10: float | None
property d30: float | None
property d50: float | None

Median grain size D50, mm – the key input to HEC-18 scour.

property d60: float | None
d_size(percent: float) float | None[source]

Particle size (mm) at which percent of the sample is finer (e.g. d_size(50) is D50), log-linearly interpolated; None if the curve does not bracket that percentage.

depth_ft: float
property fines_percent: float | None

Percent finer than the No. 200 sieve (0.075 mm).

percent_passing_at(size_mm: float) float | None[source]

Percent finer than size_mm by log-linear interpolation on the gradation curve; None if outside the measured range.

points: tuple[GradingPoint, ...]
class civilpy.geotech.boring.SPTResult(depth_ft: float, increments: tuple[DriveIncrement, ...], hammer_type: str | None = None, hammer_efficiency: str | None = None)[source]

Bases: object

One Standard Penetration Test at depth_ft (top of the 18-inch drive). increments are the successive 6-inch drives in order (seating, then the two that count).

depth_ft: float
hammer_efficiency: str | None = None
hammer_type: str | None = None
increments: tuple[DriveIncrement, ...]
n60(energy_ratio: float = 0.6, rod_length_ft: float | None = None, borehole_diameter_in: float = 4.0, liner: bool = False) float | None[source]

Energy-corrected blow count N60 (Skempton 1986): N60 = N * (Em/0.60) * Cr * Cb * Cs, where energy_ratio Em is the measured/rated hammer efficiency as a decimal. Rod-length Cr is applied from rod_length_ft (taken as depth_ft when omitted), borehole Cb from borehole_diameter_in, sampler Cs from liner.

property n_value: int | None

the sum of the second and third 6-inch increments (ASTM D1586). With only two increments their sum is used; with fewer than two, None.

Type:

Field SPT blow count N

property refusal: bool

True if the spoon did not advance the full nominal length (driven penetration short of 6 in per recorded increment).

property total_blows: int
property total_penetration_in: float
class civilpy.geotech.boring.Sample(depth_top_ft: float, depth_bottom_ft: float, method: str | None = None, recovery_in: float | None = None)[source]

Bases: object

A recovered sample interval (split spoon, Shelby tube, rock core).

depth_bottom_ft: float
depth_top_ft: float
property length_in: float
method: str | None = None
recovery_in: float | None = None
property recovery_percent: float | None

civilpy.geotech.boring_io module

Readers that turn published boring-log deliverables into the canonical Borehole objects.

The primary, near-lossless path is DIGGS (Data Interchange for Geotechnical and Geoenvironmental Specialists) XML – the structured export many DOTs publish alongside the rendered PDF log. Ohio DOT, for example, serves a DIGGS_URL for each hole on its TIMS geotechnical layer; that file carries the borehole geometry, every SPT drive set, and the full particle-size curve, so no character-window scraping is needed.

A DIGGS document is GML-based and heavily namespaced; this reader matches on local element names so it is agnostic to the schema version (2.5.a, 2.6, …) and to namespace-prefix churn. Only the standard library (xml.etree.ElementTree) is used.

PDF log ingestion (for the raster/scanned holes that have no DIGGS file) is a separate, lower-fidelity concern handled by read_pdf_log().

civilpy.geotech.boring_io.parse_diggs(source) list[Borehole][source]

Parse a DIGGS document into a list of Borehole.

source may be a file path, an open file/bytes, or a string of XML. Every Borehole sampling feature becomes one object; the SPT and particle-size Test records and the SamplingActivity sample intervals are attached to their borehole by samplingFeatureRef.

civilpy.geotech.boring_io.read_pdf_log(path) Borehole[source]

Best-effort reader for a rendered PDF boring log.

Most published logs are raster/scanned PDFs with no text layer, which require OCR and template-specific table recovery; that lower-fidelity path is not yet implemented. Prefer parse_diggs() whenever a DIGGS file is available for the hole.

civilpy.geotech.cande_adapter module

Turn a boring log into CANDE soil zones.

civilpy.structural.cande builds a buried-culvert model from three soil materials (in situ, bedding, fill). This adapter derives those SoilMaterial objects from the measured Borehole: an SPT-based linear-elastic soil for the in-situ ground, or a canned Duncan/Selig material chosen from the gradation and a target compaction for engineered fill/bedding.

The elastic moduli come from the SPT correlations in civilpy.geotech.spt; they are estimates and should yield to a laboratory-characterised soil when one exists.

civilpy.geotech.cande_adapter.clay_soil_material_from_spt(n60: float, modulus_ratio: float = 300.0, su_factor_psf: float = 92.0, poisson: float | None = None, density_pcf: float | None = None, name: str | None = None) SoilMaterial[source]

A linear-elastic SoilMaterial for a fine-grained soil: Su from N60 (Stroud), then Eu = modulus_ratio * Su.

civilpy.geotech.cande_adapter.duncan_selig_from_gradation(grading: GradingResult, compaction_percent: float, density_pcf: float, fine_group: str = 'ML') SoilMaterial[source]

Pick a canned Duncan/Selig SoilMaterial for engineered fill/bedding from a gradation and a target compaction.

Coarse soils (fines < 50%) map to the gravelly-sand SW family; fine soils map to fine_group ("ML" sandy silt by default, "CL" for plastic clays). The canned material nearest compaction_percent standard Proctor is selected.

civilpy.geotech.cande_adapter.in_situ_soil_material(borehole: Borehole, depth_ft: float, energy_ratio: float = 0.6, sigma_v_eff_psf: float | None = None, density_pcf: float | None = None, name: str | None = None) SoilMaterial[source]

The in-situ CANDE soil zone for borehole at depth_ft.

Uses the SPT nearest the depth, classifies coarse vs fine from the nearest gradation (fines >= 50% -> clay path), and returns the matching linear-elastic SoilMaterial. Raises if the hole has no SPT data near the depth.

civilpy.geotech.cande_adapter.soil_material_from_spt(n: float, soil_type: str = 'sand', poisson: float | None = None, density_pcf: float | None = None, name: str | None = None) SoilMaterial[source]

A linear-elastic SoilMaterial from an SPT N value.

soil_type is one of the Bowles coarse-grained categories (see civilpy.geotech.spt.elastic_modulus_from_spt()). Young’s modulus comes from N; Poisson’s ratio and unit weight default by soil type and N unless given.

civilpy.geotech.culmanns module

Culmann’s graphical method for active earth pressure.

Reproduces the classic Culmann construction for a retaining wall backfill loaded by a Cooper E80 railroad surcharge, computing trial-wedge weights and the governing failure plane, and plotting the construction with matplotlib.

class civilpy.geotech.culmanns.CulmannsMethod(coordinates_list=None, soil_unit_weight=<Quantity(117.7, 'force_pound / foot ** 3')>, soil_angle_int_friction=<Quantity(29.8, 'degree')>, angle_back_wall_with_horizontal=<Quantity(0, 'degree')>, angle_of_wall_friction_delta=<Quantity(0, 'degree')>, angle_of_wall_friction_gamma=<Quantity(90, 'degree')>, load_scale=<Quantity(2.9059, 'kip / foot')>, wall_height=<Quantity(19.5, 'foot')>, soil_height_above_wall=<Quantity(4.4, 'foot')>, num_slices=19, total_length=<Quantity(38, 'foot')>, track_offset=<Quantity(2, 'foot')>)[source]

Bases: object

Implements Culmann’s graphical method for lateral earth pressure.

Culmann’s method is a graphical/tabular approach for determining the maximum active lateral earth pressure on a retaining wall under arbitrary backfill geometry and surcharge loading. This class builds the calculation spreadsheet and provides plotting utilities.

table

Spreadsheet of intermediate Culmann calculations (a_i, b_i, c_i, wedge areas, weights, x/y coordinates, and resultant forces).

Type:

pandas.DataFrame

__init__(coordinates_list=None, soil_unit_weight=<Quantity(117.7, 'force_pound / foot ** 3')>, soil_angle_int_friction=<Quantity(29.8, 'degree')>, angle_back_wall_with_horizontal=<Quantity(0, 'degree')>, angle_of_wall_friction_delta=<Quantity(0, 'degree')>, angle_of_wall_friction_gamma=<Quantity(90, 'degree')>, load_scale=<Quantity(2.9059, 'kip / foot')>, wall_height=<Quantity(19.5, 'foot')>, soil_height_above_wall=<Quantity(4.4, 'foot')>, num_slices=19, total_length=<Quantity(38, 'foot')>, track_offset=<Quantity(2, 'foot')>)[source]

Initialise the Culmann’s method calculator and generate the table.

Parameters:
  • coordinates_list (dict, optional) – Dictionary of labelled coordinate points defining the wall geometry and trial wedge locations. Defaults to default_coordinates_list built from Cooper E80 loading.

  • soil_unit_weight (pint.Quantity) – Unit weight of the retained soil (default 117.7 lbf/ft³).

  • soil_angle_int_friction (pint.Quantity) – Angle of internal friction φ (default 29.8°).

  • angle_back_wall_with_horizontal (pint.Quantity) – Angle α between the back of the wall and horizontal (default 0°).

  • angle_of_wall_friction_delta (pint.Quantity) – Wall friction angle δ (default 0°).

  • angle_of_wall_friction_gamma (pint.Quantity) – Angle γ used in the force polygon construction (default 90°).

  • load_scale (pint.Quantity) – Scale factor converting cumulative wedge weight to plot coordinates (default 2.9059 kips/ft).

  • wall_height (pint.Quantity) – Height of the retaining wall (default 19.5 ft).

  • soil_height_above_wall (pint.Quantity) – Height of soil above the wall top (default 4.4 ft).

  • num_slices (int) – Number of trial wedge slices (default 19).

  • total_length (pint.Quantity) – Total horizontal extent of the backfill area (default 38 ft).

  • track_offset (pint.Quantity) – Horizontal offset to the first trial point (default 2 ft).

calculate_A_i(s_i, a_i, b_i, c_i)[source]

Calculate area A_i (ft^2) using the formula provided.

calculate_a_i(x_val, y_val)[source]

Calculate a_i (ft) based on the current coordinates.

calculate_b_i(current_key, keys, coordinates_list, x_val, y_val)[source]

Calculate b_i (ft) using the previous point’s coordinates.

calculate_c_i(current_key, keys, coordinates_list)[source]

Calculate c_i (ft) based on the previous coordinates. If first point, refer to point ‘A’.

calculate_cumulative_weights(values)[source]

Calculate cumulative weights (lbf/ft) for a list of values.

calculate_ll_surcharge(b_i)[source]

Calculate the live-load surcharge for a wedge slice per unit wall length.

Uses a simplified Cooper E80 equivalent strip load distribution. The E80 axle load (80 000 lbf) is distributed over a 4-rail area (18 ft tie spacing × 8.5 ft track width) and integrated over the wedge base length b_i.

Parameters:

b_i (pint.Quantity) – Length of the wedge base segment b_i (ft).

Returns:

Live load surcharge contribution (lbf/ft).

Return type:

pint.Quantity

calculate_running_total(values)[source]

Calculate running total (ft) for a list of values.

calculate_s_i(a_i, b_i, c_i)[source]

Calculate s_i (ft) as the semi-perimeter of the triangle.

calculate_w_i(A_i, soil_unit_weight)[source]

Calculate w_i (lbf/ft) as the incremental weight of the triangle per unit length.

calculate_x_cgi(x_val, next_x_val)[source]

Calculate x_{cgi} (ft) as the center of gravity x-coordinate.

calculate_x_ci(total_weight, load_scale, soil_angle_int_friction)[source]

Calculate x_ci (dimensionless plotting coordinate on the force polygon).

Converts total wedge weight to a force-polygon x-coordinate by dividing by the load scale (converted to matching units) and projecting onto the friction angle direction.

Parameters:
  • total_weight (pint.Quantity) – Total cumulative wedge weight in lbf/ft.

  • load_scale (pint.Quantity) – Force-polygon scale factor in kips/ft.

  • soil_angle_int_friction (pint.Quantity) – Angle of internal friction φ.

Returns:

The x_ci plotting coordinate (dimensionless).

Return type:

float

calculate_x_ci_prime(y_ci, x_ci, angle_back_wall_with_horizontal, angle_of_wall_friction_delta, soil_angle_int_friction, D, C)[source]
calculate_y_cgi(y_val, next_y_val)[source]

Calculate y_{cgi} (ft) as the center of gravity y-coordinate.

calculate_y_ci(x_ci, soil_angle_int_friction)[source]

Calculate y_ci (dimensionless plotting coordinate on the force polygon).

Parameters:
  • x_ci (float) – The x_ci plotting coordinate (dimensionless).

  • soil_angle_int_friction (pint.Quantity) – Angle of internal friction φ.

Returns:

The y_ci plotting coordinate (dimensionless).

Return type:

float

generate_spreadsheet(coordinates_list, soil_unit_weight, load_scale, soil_angle_int_friction, angle_back_wall_with_horizontal, angle_of_wall_friction_delta)[source]

Calculate various columns for soil and wall friction analysis.

Args: coordinates_list (dict): Dictionary containing coordinate points. soil_unit_weight (float): The unit weight of the soil. load_scale (float): Load scale value. soil_angle_int_friction (float): Angle of internal friction of soil in radians. angle_back_wall_with_horizontal (float): Angle between back of wall and horizontal in radians. angle_of_wall_friction_delta (float): Angle of wall friction in radians.

Returns: pd.DataFrame: DataFrame containing computed columns.

plot_results()[source]

Plot the retaining wall geometry and Culmann’s method construction.

Generates a matplotlib figure showing:

  • Trial wedge points (C_1 … C_n) and the base points A and B.

  • Dashed green lines connecting each C-point back to B.

  • The ground surface line from A through all C-points.

  • A trapezoidal retaining wall cross-section.

The figure is displayed via plt.show().

sort_keys(keys)[source]

Sort C-point keys numerically by their integer suffix.

Parameters:

keys (list[str]) – List of keys in the form "C_1", "C_2", etc.

Returns:

Keys sorted in ascending numerical order.

Return type:

list[str]

civilpy.geotech.culmanns.build_coordinates_list(starting_coordinates_list={'A': (0, 23.9, 'LS1'), 'B': (0, 0, None), 'C_1': (2.0, 19.5, 'LS1'), 'C_10': (20.0, 19.5, 'LS1'), 'C_11': (22.0, 19.5, None), 'C_12': (24.0, 19.5, None), 'C_13': (26.0, 19.5, 'LS2'), 'C_14': (28.0, 19.5, 'LS2'), 'C_15': (30.0, 19.5, 'LS2'), 'C_16': (32.0, 19.5, 'LS2'), 'C_17': (34.0, 19.5, 'LS2'), 'C_18': (36.0, 19.5, 'LS2'), 'C_19': (38.0, 19.5, 'LS2'), 'C_2': (4.0, 19.5, 'LS1'), 'C_3': (6.0, 19.5, 'LS1'), 'C_4': (8.0, 19.5, 'LS1'), 'C_5': (10.0, 19.5, 'LS1'), 'C_6': (12.0, 19.5, 'LS1'), 'C_7': (14.0, 19.5, 'LS1'), 'C_8': (16.0, 19.5, 'LS1'), 'C_9': (18.0, 19.5, 'LS1')}, total_length=38, num_slices=19, track_offset=2, wall_height=19.5, soil_height_above_wall=0)[source]

Populate a Culmann’s method coordinate dictionary with trial wedge points.

Adds num_slices C-points ("C_1""C_n") to starting_coordinates_list. Each point represents the top of a trial failure wedge at a horizontal spacing of total_length / num_slices starting from track_offset.

Parameters:
  • starting_coordinates_list (dict) – Base dictionary containing at least the fixed "A" (wall top) and "B" (wall toe) points.

  • total_length (float) – Horizontal extent of the soil wedge area (ft).

  • num_slices (int) – Number of trial wedge points to generate.

  • track_offset (float) – Horizontal offset from the wall face to the first trial point (ft).

  • wall_height (float) – Height of the retaining wall (ft).

  • soil_height_above_wall (float) – Additional soil height above the wall top (ft).

Returns:

Updated coordinate dictionary with the new C-points added.

Return type:

dict

civilpy.geotech.culmanns.find_key_for_value_in_tuple_range(data, number)[source]

Find the key in a dictionary where the number falls between the first two values of the tuple.

Args: data (dict): Dictionary containing lists of tuples. number (float): The number to search for within the tuple ranges.

Returns: key: The key in the dictionary whose tuple contains the number, or None if not found.

civilpy.geotech.deep_foundation module

Axial capacity of deep foundations from a boring log.

Two methods share one boring-driven integrator:

  • Drilled shafts – FHWA / AASHTO LRFD Article 10.8 (O’Neill & Reese, FHWA GEC-10): the alpha method for side and tip resistance in cohesive soil and the beta method for cohesionless soil.

  • Driven piles – the Meyerhof (1976) SPT method for cohesionless soil (unit skin friction and end bearing from N60) plus the alpha method in clay, consistent with AASHTO 10.7.3.8.6.

The unit-resistance functions are the citable core; the drilled_shaft_capacity() and driven_pile_capacity() drivers discretise the element, pull soil properties at each depth from a Borehole (blow counts via civilpy.geotech.spt), integrate side resistance, and add tip resistance.

Soil parameters derived from SPT are estimates; a foundation for final design should be checked against a project-specific subsurface characterisation. The Meyerhof method in particular is known to be unconservative for end bearing in dense sand.

Units: lengths in feet, unit weights in pcf, stresses and unit resistances in ksf, capacities in kips, angles in degrees.

civilpy.geotech.deep_foundation.GAMMA_WATER_PCF = 62.4

Unit weight of water, pcf.

civilpy.geotech.deep_foundation.PA_KSF = 2.116

Atmospheric pressure, ksf (used to normalise Su for the alpha factor).

class civilpy.geotech.deep_foundation.PileCapacity(width_ft: float, tip_depth_ft: float, side_nominal_kips: float, tip_nominal_kips: float)[source]

Bases: object

Result of driven_pile_capacity(): nominal resistances (kips) and the pile geometry that produced them.

factored_kips(phi_side: float = 0.45, phi_tip: float = 0.45) float[source]

Factored axial resistance (kips). Defaults are representative AASHTO 10.5.5.2.3 driven-pile resistance factors for the SPT-based methods; pass the values for the controlling soil and method.

side_nominal_kips: float
tip_depth_ft: float
tip_nominal_kips: float
property total_nominal_kips: float
width_ft: float
class civilpy.geotech.deep_foundation.ShaftCapacity(diameter_ft: float, tip_depth_ft: float, side_nominal_kips: float, tip_nominal_kips: float)[source]

Bases: object

Result of drilled_shaft_capacity(): nominal resistances (kips) and the shaft geometry that produced them.

diameter_ft: float
factored_kips(phi_side: float = 0.45, phi_tip: float = 0.4) float[source]

Factored axial resistance (kips). Defaults are conservative AASHTO 10.5.5.2.4 drilled-shaft resistance factors (clay side 0.45, clay tip 0.40); pass the values matching the controlling soil.

side_nominal_kips: float
tip_depth_ft: float
tip_nominal_kips: float
property total_nominal_kips: float
civilpy.geotech.deep_foundation.alpha_factor(su_ksf: float) float[source]

Adhesion factor alpha for drilled-shaft side resistance in clay (AASHTO LRFD 10.8.3.5.1b, O’Neill & Reese):

alpha = 0.55 for Su/pa <= 1.5 alpha = 0.55 - 0.1 (Su/pa - 1.5) for 1.5 < Su/pa <= 2.5

civilpy.geotech.deep_foundation.beta_factor(depth_ft: float, n60: float) float[source]

Side-resistance factor beta for sand (AASHTO 10.8.3.5.2b, O’Neill & Reese): beta = 1.5 - 0.135 sqrt(z), 0.25 <= beta <= 1.2, with a linear reduction by N60/15 for loose sand (N60 < 15). z in feet.

civilpy.geotech.deep_foundation.drilled_shaft_capacity(borehole: Borehole, diameter_ft: float, tip_depth_ft: float, water_table_ft: float | None = None, energy_ratio: float = 0.6, step_ft: float = 0.5, su_factor_psf: float = 92.0, exclude_top_ft: float = 5.0, exclude_bottom_diameters: float = 1.0) ShaftCapacity[source]

Nominal axial (compression) capacity of a straight drilled shaft.

Discretises the shaft into step_ft elements, derives soil properties at each from borehole (cohesive vs cohesionless by gradation fines, blow counts energy-corrected to N60), integrates the effective vertical stress, and sums side resistance – excluding the top exclude_top_ft and the bottom exclude_bottom_diameters diameters per AASHTO 10.8.3.5 – then adds tip resistance at the base.

water_table_ft overrides the boring’s recorded water strike; with neither, fully drained (no pore pressure) is assumed.

civilpy.geotech.deep_foundation.driven_pile_capacity(borehole: Borehole, width_ft: float, tip_depth_ft: float, perimeter_ft: float | None = None, area_ft2: float | None = None, displacement: bool = True, alpha_clay: float = 0.55, water_table_ft: float | None = None, energy_ratio: float = 0.6, step_ft: float = 0.5, su_factor_psf: float = 92.0) PileCapacity[source]

Nominal axial (compression) capacity of a driven pile.

Discretises the pile, derives soil properties at each element from borehole (cohesive vs cohesionless by gradation fines), and sums skin friction over the full embedded length – Meyerhof fs = m Pa N60 in sand, alpha * Su in clay – then adds end bearing at the tip (Meyerhof in sand, 9 Su in clay).

width_ft is the pile diameter/width. By default a solid round/ square section is assumed (perimeter pi*B, area pi*B^2/4); pass perimeter_ft and area_ft2 for H-piles or open sections. displacement selects the Meyerhof skin-friction coefficient.

civilpy.geotech.deep_foundation.meyerhof_unit_end_bearing_sand(n60: float, embedment_ratio: float, pa_ksf: float = 2.116) float[source]

Nominal unit end bearing (ksf) of a driven pile in cohesionless soil (Meyerhof 1976): qp = 0.4 Pa N60 (Lb/D) <= 4 Pa N60, where embedment_ratio Lb/D is the embedment in the bearing stratum over the pile width.

civilpy.geotech.deep_foundation.meyerhof_unit_skin_friction_sand(n60: float, displacement: bool = True, pa_ksf: float = 2.116) float[source]

Nominal unit skin friction (ksf) of a driven pile in cohesionless soil (Meyerhof 1976): fs = m * Pa * N60, with m = 0.02 for large- displacement piles (closed-end pipe, precast) and 0.01 for small- displacement piles (H-piles, open-end pipe).

civilpy.geotech.deep_foundation.pile_unit_skin_friction_clay(su_ksf: float, alpha: float = 0.55) float[source]

Nominal unit skin friction (ksf) of a driven pile in cohesive soil by the alpha (total-stress) method: fs = alpha * Su. alpha follows Tomlinson/API and ranges from ~0.5 (stiff clay) to 1.0 (soft clay).

civilpy.geotech.deep_foundation.unit_side_resistance_clay(su_ksf: float) float[source]

Nominal unit side resistance in cohesive soil (ksf): q_s = alpha * Su (AASHTO 10.8.3.5.1b).

civilpy.geotech.deep_foundation.unit_side_resistance_sand(sigma_v_eff_ksf: float, depth_ft: float, n60: float, limit_ksf: float = 4.0) float[source]

Nominal unit side resistance in cohesionless soil (ksf): q_s = beta * sigma’_v, capped at limit_ksf (AASHTO 10.8.3.5.2b).

civilpy.geotech.deep_foundation.unit_tip_resistance_clay(su_ksf: float, depth_ft: float, diameter_ft: float, limit_ksf: float = 80.0) float[source]

Nominal unit tip resistance in cohesive soil (ksf), AASHTO 10.8.3.5.1c: q_p = Nc * Su, Nc = 6[1 + 0.2 (Z/D)] <= 9, capped at limit_ksf.

civilpy.geotech.deep_foundation.unit_tip_resistance_sand(n60: float, limit_ksf: float = 60.0) float[source]

Nominal unit tip resistance in cohesionless soil (ksf), AASHTO 10.8.3.5.2c (O’Neill & Reese): q_p = 1.2 N60 for N60 <= 50, capped at limit_ksf (60 ksf).

civilpy.geotech.lateral_earth module

Rankine and Coulomb lateral earth pressure with the classic pressure- diagram plot — companions to the Culmann graphical method already in civilpy.geotech.culmanns.

Units: ft, pcf inputs; pressures plotted in psf.

Examples

>>> round(rankine_ka(30), 4)
0.3333
>>> round(rankine_kp(30), 1)
3.0
>>> wall = LateralEarthPressure(height=12, gamma=120, phi=30)
>>> round(wall.resultant, 0)   # 0.5*Ka*gamma*H^2 = 2880 lb/ft
2880.0
class civilpy.geotech.lateral_earth.LateralEarthPressure(height: float, gamma: float, phi: float, surcharge: float = 0.0, water_depth: float | None = None, k: float | None = None, passive: bool = False)[source]

Bases: object

Active (or passive) pressure diagram on a wall of height ft retaining soil of unit weight gamma pcf and friction angle phi deg, with optional uniform surcharge (psf) and water table depth (ft below the top).

plot(ax=None)[source]

Pressure-diagram plot: wall on the left, pressure wedge growing with depth, resultant arrow at its centroid.

pressure_at(z: float) float[source]

Total lateral pressure (psf) at depth z ft: soil (buoyant below the water table) plus full water plus surcharge.

property resultant: float

Total thrust per ft of wall (lb/ft), by numeric integration.

property resultant_height: float

Height of the thrust above the wall base (ft).

civilpy.geotech.lateral_earth.coulomb_ka(phi_deg: float, delta_deg: float = 0.0, beta_deg: float = 0.0, theta_deg: float = 0.0) float[source]

Coulomb active coefficient: wall friction delta, backfill slope beta, wall back-face batter theta from vertical.

civilpy.geotech.lateral_earth.rankine_ka(phi_deg: float, beta_deg: float = 0.0) float[source]

Rankine active coefficient; beta_deg is the backfill slope. With a level backfill this is the familiar (1-sin)/(1+sin).

civilpy.geotech.lateral_earth.rankine_kp(phi_deg: float, beta_deg: float = 0.0) float[source]

Rankine passive coefficient.

civilpy.geotech.lateral_pile module

Laterally loaded piles: a shared p-y curve library, a finite-element beam-on-nonlinear-foundation solver, Broms’ closed-form ultimate-load method, and the characteristic-length / subgrade-reaction hand methods.

The p-y curve classes (SoftClayPY, StiffClayPY, SandPY, LinearPY) are the reusable core: they expose a common p(y, z) (soil resistance per unit length) and pu(z) (ultimate resistance) so the same soil models drive both the in-process solver here and the LPILE input-file generator in civilpy.geotech.lpile.

Curve references: soft clay – Matlock (1970); stiff clay without free water – Reese & Welch (1975); sand – the API RP 2A / O’Neill & Murchison hyperbolic-tangent form on Reese’s (1974) ultimate resistance.

Units throughout this module are inches, pounds, and psi (so unit weights are pci and the flexural stiffness EI is lb-in^2), matching the convention LPILE uses. Angles are in degrees.

class civilpy.geotech.lateral_pile.BromsResult(h_ult: float, mode: str, h_short: float, h_long: float, f_maxmoment: float | None = None)[source]

Bases: object

Ultimate lateral load by Broms’ method and the governing mechanism.

f_maxmoment: float | None = None
h_long: float
h_short: float
h_ult: float
mode: str
class civilpy.geotech.lateral_pile.LateralPileResult(depth: ndarray, deflection: ndarray, moment: ndarray, shear: ndarray, soil_reaction: ndarray, iterations: int, converged: bool)[source]

Bases: object

Depth-wise response of a laterally loaded pile.

converged: bool
deflection: ndarray
depth: ndarray
property head_deflection: float
iterations: int
property max_moment: float
property max_moment_depth: float
moment: ndarray
plot(ax=None)[source]

Four-panel deflection / moment / shear / soil-reaction profile.

property point_of_fixity: float | None

Depth (in) of the first sign change in deflection below the head – the classic ‘point of fixity’. None if the pile never reverses.

shear: ndarray
soil_reaction: ndarray
class civilpy.geotech.lateral_pile.LinearPY(k: float, p_ult: float = inf)[source]

Bases: PYCurve

A constant-modulus Winkler spring p = k*y (k in psi). Mostly for verifying the solver against the closed-form subgrade-reaction solution, but also a valid simple model.

k: float
p(y: float, z: float) float[source]
p_ult: float = inf
pu(z: float) float[source]
civilpy.geotech.lateral_pile.MATLOCK_REESE_AY = 2.435

Matlock-Reese non-dimensional coefficients at the ground surface (Z = 0) for a long, free-headed pile in soil with linearly increasing modulus.

class civilpy.geotech.lateral_pile.PYCurve[source]

Bases: object

Base class for p-y curves. Subclasses implement p() and pu(); the secant modulus used by the solver follows from them.

p(y: float, z: float) float[source]
pu(z: float) float[source]
secant_modulus(y: float, z: float) float[source]

Secant soil modulus Es = p/y (psi) at deflection y and depth z; uses a deflection floor so it stays finite at y = 0.

class civilpy.geotech.lateral_pile.SandPY(phi_deg: float, gamma: float, b: float, k: float | None = None, submerged: bool = False, static: bool = True)[source]

Bases: PYCurve

API RP 2A / O’Neill & Murchison sand p-y curve on Reese’s ultimate resistance: p = A*pu*tanh(k*z*y/(A*pu)).

phi_deg friction angle, gamma effective unit weight (pci), b diameter (in), k initial subgrade modulus (pci; defaults from sand_subgrade_modulus()), submerged selects the k table, and static the A-factor (max(3 - 0.8 z/b, 0.9) static, 0.9 cyclic).

a_factor(z: float) float[source]
b: float
gamma: float
k: float | None = None
p(y: float, z: float) float[source]
phi_deg: float
pu(z: float) float[source]
static: bool = True
submerged: bool = False
class civilpy.geotech.lateral_pile.SoftClayPY(cu: float, b: float, gamma: float, eps50: float = 0.02, J: float = 0.5, static: bool = True)[source]

Bases: PYCurve

Matlock (1970) soft-clay p-y curve.

cu undrained shear strength (psi), b pile diameter (in), gamma effective unit weight (pci), eps50 strain at half the ultimate stress, J the empirical factor (0.5 soft / 0.25 stiffer field clays). static selects the static backbone (the cyclic curve flattens at 0.72*pu below the critical depth).

J: float = 0.5
b: float
cu: float
eps50: float = 0.02
gamma: float
p(y: float, z: float) float[source]
pu(z: float) float[source]
static: bool = True
property y50: float
class civilpy.geotech.lateral_pile.StiffClayPY(cu: float, b: float, gamma: float, eps50: float = 0.007, J: float = 0.5)[source]

Bases: PYCurve

Reese & Welch (1975) stiff clay without free water.

Same ultimate resistance as Matlock but a flatter backbone p = 0.5*pu*(y/y50)^0.25 reaching pu at 16*y50, with y50 = eps50*b.

J: float = 0.5
b: float
cu: float
eps50: float = 0.007
gamma: float
p(y: float, z: float) float[source]
pu(z: float) float[source]
property y50: float
class civilpy.geotech.lateral_pile.SubgradeResponse(head_deflection: float, head_slope: float, max_moment: float, characteristic_length: float, point_of_fixity: float)[source]

Bases: object

Pile-head response from a closed-form subgrade-reaction analysis.

characteristic_length: float
head_deflection: float
head_slope: float
max_moment: float
point_of_fixity: float
civilpy.geotech.lateral_pile.broms_cohesionless(phi_deg: float, gamma: float, b: float, length: float, yield_moment: float, e: float = 0.0) BromsResult[source]

Broms (1964) ultimate lateral load of a free-headed pile in cohesionless soil, using a passive resistance 3*Kp*gamma*z*b (Rankine Kp).

gamma effective unit weight (pci), other arguments as in broms_cohesive(). Short pile: Hu = 0.5*Kp*gamma*b*L^3/(e+L); long pile: Mmax = Hu(e + 2f/3) = My with f = sqrt(Hu/(1.5 Kp gamma b)).

civilpy.geotech.lateral_pile.broms_cohesive(cu: float, b: float, length: float, yield_moment: float, e: float = 0.0) BromsResult[source]

Broms (1964) ultimate lateral load of a free-headed pile in cohesive soil. Resistance is neglected over the top 1.5*b and taken as 9*cu*b below it.

cu undrained shear strength (psi), b diameter (in), length embedded length (in), yield_moment plastic moment of the pile section (lb-in), e load height above ground (in). The lesser of the short-pile (soil) and long-pile (yield) failures governs.

civilpy.geotech.lateral_pile.reese_sand_pu(phi_deg: float, gamma: float, b: float, z: float) float[source]

Reese (1974) ultimate sand resistance per unit length (lb/in), the lesser of the wedge (shallow) and flow-around (deep) failure values.

phi_deg friction angle, gamma effective unit weight (pci), b diameter (in), z depth (in).

civilpy.geotech.lateral_pile.sand_subgrade_modulus(phi_deg: float, submerged: bool = False) float[source]

Typical initial modulus of subgrade reaction k (pci) for sand from the API RP 2A / Reese charts, interpolated on friction angle. These are order-of-magnitude design values; use project-specific data when available.

civilpy.geotech.lateral_pile.solve_lateral_pile(curves, length: float, ei: float, shear: float, moment: float = 0.0, n_elem: int = 100, fixed_head: bool = False, max_iter: int = 100, tol: float = 1e-06, relax: float = 0.5) LateralPileResult[source]

Solve a laterally loaded pile by finite elements on nonlinear p-y springs (the in-process equivalent of an LPILE run).

curves is one PYCurve for the whole pile or a callable curve(z) returning the curve at depth z (in). length is the embedded length (in), ei the flexural stiffness (lb-in^2), and shear/moment the load applied at the pile head (lb, lb-in). A fixed_head pile has zero head rotation. Soil springs use the secant modulus and are iterated with under-relaxation relax until the head deflection settles within tol.

civilpy.geotech.lateral_pile.subgrade_constant_k(k: float, ei: float, shear: float, moment: float = 0.0) SubgradeResponse[source]

Long pile in soil of constant modulus k (psi) – the Hetenyi semi-infinite beam-on-elastic-foundation solution.

beta = (k/(4 EI))^{1/4}; head deflection y0 = 2 beta (P + beta M)/k and slope -2 beta^2 (P + 2 beta M)/k for head shear P and moment M. The point of fixity is taken at the rule-of-thumb 1.4/beta.

civilpy.geotech.lateral_pile.subgrade_linear_nh(nh: float, ei: float, shear: float, moment: float = 0.0) SubgradeResponse[source]

Long pile in soil of linearly increasing modulus Es = nh*z (nh in pci) – the Matlock-Reese non-dimensional solution for a free head.

Relative stiffness T = (EI/nh)^{1/5}; ground-line deflection y_g = Ay P T^3/EI + By M T^2/EI and maximum moment ~Am P T (plus the applied head moment). Point of fixity is taken at the common 1.8 T for sand.

civilpy.geotech.lpile module

LPILE (Ensoft) integration: input-file generation and output parsing.

LPILE has no COM/SDK automation interface, so – following the same codegen-run-parse pattern as the CANDE box-culvert wrapper in civilpy.structural.cande – this module integrates through LPILE’s versioned ASCII data-file format. An LPileModel carries the pile section, the soil layers (each backed by a p-y curve from civilpy.geotech.lateral_pile, so the same models drive both the in-process solver and the LPILE run), and the pile-head loading; it emits a data file with LPileModel.to_lpd(). Output is read back from an LPILE text report with parse_lpile_report() into an LPileResults object holding the depth-wise deflection / moment / shear / soil-reaction profiles and the pile-head response, with plotly plot helpers.

Because LPILE is rarely installed alongside civilpy, LPileModel.simulate() runs the equivalent analysis with civilpy’s own finite-element p-y solver and returns the same LPileResults, so a model is fully usable (and round-trips through the report format) without the Ensoft engine.

Soil layering can be sourced from a SoilProfile (and therefore from a parsed DIGGS boring) via LPileModel.from_soil_profile().

Units: inches, pounds, psi (unit weights pci), matching LPILE’s English unit set and civilpy.geotech.lateral_pile.

civilpy.geotech.lpile.DATA_FORMAT_VERSION = 11

LPILE ASCII data-file format this module targets. LPILE’s data exchange file is versioned (“Data Format Version 9/10/11”); we pin 11.

class civilpy.geotech.lpile.LPileLoad(shear: float, moment: float = 0.0, axial: float = 0.0, condition: int = 1, slope: float = 0.0)[source]

Bases: object

Pile-head loading. condition 1 = shear + moment (free head), 2 = shear + slope (slope in radians, 0 for a fixed head). Forces in lb / lb-in.

axial: float = 0.0
condition: int = 1
moment: float = 0.0
shear: float
slope: float = 0.0
class civilpy.geotech.lpile.LPileModel(section: PileSection, layers: list[LPileSoilLayer], load: LPileLoad, n_increments: int = 100, cyclic: bool = False, n_cycles: int = 1, title: str | None = None)[source]

Bases: object

An LPILE single-pile model: section, soil layers, and head loading.

curve_at(depth: float) PYCurve[source]

The p-y curve governing a given depth (in); the deepest layer extends below its nominal bottom.

classmethod from_soil_profile(profile: SoilProfile, curves: list[PYCurve], section: PileSection, load: LPileLoad, **kwargs) LPileModel[source]

Build a model whose layers follow a SoilProfile (feet, pcf), converting depths to inches. curves is one p-y curve per soil layer (top to bottom).

run(work_dir=None, prefix: str = 'pile', lpile_exe=None) LPileResults[source]

Run the model through an installed LPILE engine. LPILE has no automation API, so this writes the data file, invokes the LPILE command-line executable on it, and parses the text report. Raises if no executable is available – use simulate() to analyze without Ensoft LPILE.

simulate(**solver_kwargs) LPileResults[source]

Run the analysis with civilpy’s own FE p-y solver (no Ensoft engine needed) and return LPileResults.

to_lpd() str[source]

The complete LPILE ASCII data file as a string.

write_lpd(work_dir, prefix: str = 'pile') Path[source]

Write the data file to work_dir and return its path.

class civilpy.geotech.lpile.LPileResults(depth: ndarray, deflection: ndarray, moment: ndarray, shear: ndarray, soil_reaction: ndarray, pile_head_deflection: float, max_moment: float, max_moment_depth: float, pile_head_rotation: float = 0.0, source: str = 'lpile')[source]

Bases: object

Depth-wise pile response from an LPILE run or simulation.

deflection: ndarray
depth: ndarray
property lateral_stiffness: float

Secant pile-head lateral stiffness (lb/in) = head shear / head deflection, recovered from the shear at the top node.

max_moment: float
max_moment_depth: float
moment: ndarray
pile_head_deflection: float
pile_head_rotation: float = 0.0
plot()[source]

A 1x4 plotly figure of deflection / moment / shear / soil reaction vs depth (depth increasing downward).

shear: ndarray
soil_reaction: ndarray
source: str = 'lpile'
to_report_text() str[source]

Format the results as an LPILE-style text report (the inverse of parse_lpile_report()).

class civilpy.geotech.lpile.LPileSoilLayer(top: float, bottom: float, curve: PYCurve, name: str = '')[source]

Bases: object

One LPILE soil layer over a depth range, backed by a p-y curve.

top/bottom are depths below the pile head (in); curve is the PYCurve supplying both the LPILE p-y model parameters and the in-process simulation.

bottom: float
contains(depth: float) bool[source]
curve: PYCurve
property model_name: str
name: str = ''
top: float
class civilpy.geotech.lpile.PileSection(length: float, diameter: float, ei: float, modulus: float = 29000000.0, area: float | None = None)[source]

Bases: object

A prismatic pile section.

length and diameter in inches, ei the flexural stiffness (lb-in^2). area and modulus are optional (used only for the data-file fields and axial reporting); if omitted, modulus is taken as steel and area from a solid circle.

area: float | None = None
diameter: float
ei: float
length: float
modulus: float = 29000000.0
property moment_of_inertia: float

I implied by EI / modulus (in^4).

civilpy.geotech.lpile.parse_lpile_report(text: str) LPileResults[source]

Parse an LPILE text report into LPileResults.

Reads the depth / deflection / moment / shear / soil-reaction table (any block of rows with five numeric columns under a header naming Depth and Deflection) and the pile-head deflection, rotation, and maximum-moment summary lines.

civilpy.geotech.shallow_foundation module

Shallow (spread) foundation analysis and design.

Three families of routines, all pure functions or small dataclasses:

  • Bearing capacity – the general (Terzaghi / Meyerhof / Vesic) bearing capacity equation with shape, embedment-depth, and load-inclination modifiers, and Meyerhof’s effective-area reduction for eccentric loads. AASHTO LRFD 10.6.3.1; allowable-stress (factor of safety) and factored (resistance-factor) forms both fall out of one result object.

  • Contact pressure – the soil bearing-pressure distribution under a combined vertical load and moment (full-contact trapezoid, triangular with partial uplift) used to check the bearing demand and to load the footing as a structural element.

  • Settlement – Schmertmann strain-influence elastic settlement and one-dimensional primary consolidation, both able to source soil layering and effective stresses from SoilProfile.

The footing’s own structural design (one-way shear, two-way punching shear, flexural reinforcement) reuses the reinforced-concrete resistance functions in civilpy.structural.aashto.lrfd.concrete rather than re-deriving them here.

Units: feet, pounds-force, and pcf for the geotechnical side (pressures in psf, capacities reported in both psf and ksf); the structural helpers convert to the kip-inch-ksi convention the LRFD module expects. Angles in degrees.

class civilpy.geotech.shallow_foundation.BearingCapacityFactors(nc: float, nq: float, ngamma: float, method: str)[source]

Bases: object

Dimensionless bearing-capacity factors Nc, Nq, Ngamma for a given friction angle and method.

method: str
nc: float
ngamma: float
nq: float
class civilpy.geotech.shallow_foundation.BearingCapacityResult(q_ult: float, factors: BearingCapacityFactors, b_eff: float, l_eff: float, terms: dict = <factory>, modifiers: dict = <factory>)[source]

Bases: object

Ultimate bearing capacity and the pieces an engineer would tabulate.

q_ult is the gross ultimate unit bearing pressure (psf); terms holds the cohesion, surcharge, and self-weight contributions.

allowable(fs: float = 3.0) float[source]

Allowable bearing pressure (psf) = q_ult / FS (ASD).

property area_eff: float

Effective (Meyerhof) bearing area, ft^2.

b_eff: float
factored_load(phi_b: float = 0.45) float[source]

Factored bearing resistance (lb), AASHTO LRFD 10.5.5.2.2; phi_b defaults to 0.45 (theoretical/semi-empirical methods).

factors: BearingCapacityFactors
l_eff: float
modifiers: dict
nominal_load() float[source]

Nominal bearing resistance as a force (lb) = q_ult * effective area.

q_ult: float
property q_ult_ksf: float
terms: dict
class civilpy.geotech.shallow_foundation.ConsolidationLayer(layer_index: int, cc: float, e0: float, cr: float = 0.0, sigma_pc: float | None = None)[source]

Bases: object

Consolidation parameters for one compressible stratum (by index into a SoilProfile).

cc: float
cr: float = 0.0
e0: float
layer_index: int
sigma_pc: float | None = None
class civilpy.geotech.shallow_foundation.ContactPressure(q_max: float, q_min: float, width: float, length: float, eccentricity: float, contact_length: float, uplift: bool)[source]

Bases: object

Soil contact-pressure distribution under axial load p (lb) at eccentricity e (ft) on a footing of width width (ft, in the direction of the moment) and length length (ft).

contact_length: float
eccentricity: float
property full_contact: bool
length: float
q_max: float
q_min: float
uplift: bool
width: float
civilpy.geotech.shallow_foundation.GAMMA_WATER = 62.4

Unit weight of water, pcf.

class civilpy.geotech.shallow_foundation.SettlementResult(settlement_in: float, c1: float = 1.0, c2: float = 1.0, contributions: list = <factory>)[source]

Bases: object

Total settlement (in) and the correction factors / per-sublayer contributions that produced it.

c1: float = 1.0
c2: float = 1.0
contributions: list
settlement_in: float
civilpy.geotech.shallow_foundation.bearing_capacity_factors(phi_deg: float, method: str = 'vesic') BearingCapacityFactors[source]

Bearing-capacity factors for friction angle phi_deg.

Nq and Nc for Meyerhof/Hansen/Vesic are the Prandtl-Reissner forms Nq = e^(pi*tan phi)*tan^2(45 + phi/2) and Nc = (Nq - 1)*cot phi (5.14 at phi = 0). Terzaghi uses his own Nq = a^2/(2 cos^2(45 + phi/2)) with a = e^((3pi/4 - phi/2) tan phi) and Nc = 5.7 at phi = 0. Ngamma differs by method:

  • Terzaghi – 2 (Nq + 1) tan phi / (1 + 0.4 sin 4phi) (approximation)

  • Meyerhof – (Nq - 1) tan(1.4 phi)

  • Hansen – 1.5 (Nq - 1) tan phi

  • Vesic – 2 (Nq + 1) tan phi

civilpy.geotech.shallow_foundation.bearing_water_table(gamma: float, gamma_sat: float, d: float, b: float, water_table: float) tuple[float, float][source]

Surcharge q at footing level and the unit weight to use in the 0.5*gamma*B*Ngamma term, accounting for a water table at depth water_table (ft below ground). gamma is the moist weight above the table, gamma_sat the saturated weight below it. Three cases per Das: table below the failure wedge (d + b), within the wedge, and above footing level.

civilpy.geotech.shallow_foundation.consolidation_settlement(profile: SoilProfile, layers: list[ConsolidationLayer], delta_sigma, n_slices: int = 1) SettlementResult[source]

One-dimensional primary consolidation settlement (in) of the compressible layers within profile.

For each layer the initial effective stress sigma'0 is read at the layer midpoint from profile and the stress increase delta_sigma (a constant psf or a callable dsigma(depth_ft)) is added. Normally consolidated soil (or no preconsolidation given) uses the virgin curve Cc/(1+e0)*H*log10((s0+ds)/s0); over-consolidated soil uses the recompression index Cr while the final stress stays below sigma_pc and splits across sigma_pc when it is exceeded. n_slices sub-divides each layer for a better midpoint stress.

civilpy.geotech.shallow_foundation.contact_pressure(p: float, m: float, width: float, length: float) ContactPressure[source]

Bearing-pressure distribution from a vertical load p (lb) and moment m (lb-ft) on a rectangular footing.

With eccentricity e = M/P inside the middle third (e <= L/6) the pressure is trapezoidal, q = P/A * (1 +/- 6e/width). Outside the kern the heel lifts off and a triangular distribution develops over a contact length 3*(width/2 - e) with peak 2P/(length*contact) (the resultant must pass through the centroid of the triangle).

civilpy.geotech.shallow_foundation.depth_factors(d: float, b: float, phi_deg: float) tuple[float, float, float][source]

Hansen embedment-depth factors (dc, dq, dgamma). For d/b <= 1 the factor k = d/b; for deeper footings k = arctan(d/b) (radians) so the modifier stays bounded. dgamma = 1.

civilpy.geotech.shallow_foundation.footing_flexure(q_net: float, length: float, col_width: float, a_s: float, thickness_in: float, cover_in: float, f_c: float, f_y: float = 60.0, bar_dia_in: float = 1.0) CheckResult[source]

Flexural check of the footing cantilever, reusing rc_rectangular_flexural_resistance().

a_s is the reinforcement area in a 12-in design strip (in^2/ft); length/col_width (ft) set the cantilever moment. Effective depth d = thickness - cover - db/2.

civilpy.geotech.shallow_foundation.footing_flexure_demand(q_net: float, length: float, col_width: float) float[source]

Factored cantilever moment Mu (kip-in per foot of width) at the column face on a footing under net pressure q_net (psf). Span is (length - col_width)/2 (ft).

civilpy.geotech.shallow_foundation.footing_one_way_shear(q_net: float, width: float, length: float, col_width: float, thickness_in: float, cover_in: float, f_c: float, bar_dia_in: float = 1.0) CheckResult[source]

One-way shear check of a spread footing, reusing rc_shear_resistance().

thickness_in is the footing depth; d = thickness - cover - db/2. The full footing width (ft) is the shear width bv. Returns the LRFD CheckResult (capacity phi*Vn vs demand Vu).

civilpy.geotech.shallow_foundation.footing_punching_shear(p_u: float, col_b_in: float, col_l_in: float, thickness_in: float, cover_in: float, f_c: float, beta_c: float | None = None, bar_dia_in: float = 1.0, q_net: float = 0.0, lam: float = 1.0, phi_v: float = 0.9) CheckResult[source]

Two-way (punching) shear resistance at a footing (AASHTO 5.12.8.6.3):

Vn = (0.063 + 0.126/beta_c)*lam*sqrt(f’c)*b0*dv <= 0.126*lam*sqrt(f’c)*b0*dv

p_u is the factored column load (kip); the critical perimeter b0 is taken d/2 outside a rectangular column col_b x col_l (in). beta_c is the column aspect ratio (defaults to the long/short side). The net upward pressure within the critical perimeter (q_net psf) is credited back, so the demand is Pu minus that relief. Result is in kip; phi_v = 0.9.

civilpy.geotech.shallow_foundation.inclination_factors(h: float, v: float, b: float, l: float, phi_deg: float, c: float, area: float) tuple[float, float, float][source]

Vesic load-inclination factors (ic, iq, igamma) for a horizontal load h and vertical load v (consistent force units). area is the effective bearing area, c the cohesion (same pressure unit as used elsewhere). For frictionless soil (phi = 0) only the cohesion term is reduced. Raises if h exceeds the available sliding resistance.

civilpy.geotech.shallow_foundation.nq_from_phi(phi_deg: float) float[source]

Reissner Nq (used by the inclination factor’s cohesion term).

civilpy.geotech.shallow_foundation.one_way_shear_demand(q_net: float, width: float, length: float, col_width: float, d_in: float) float[source]

Factored one-way (beam) shear Vu (kip) at distance d from the column face on a footing carrying uniform net pressure q_net (psf).

The critical section is at d_in (in) from the face; the cantilever length is (length - col_width)/2 - d (ft). width is the footing dimension perpendicular to the span. Returns 0 if the section falls outside the footing.

civilpy.geotech.shallow_foundation.schmertmann_settlement(net_pressure: float, b: float, l: float, d: float, es_profile, gamma: float = 120.0, years: float = 1.0, n_sublayers: int = 20) SettlementResult[source]

Schmertmann (1978) strain-influence elastic settlement (in).

S = C1*C2*dq * sum( Iz/Es * dz )

net_pressure is the net applied pressure dq (psf); b/l the footing plan dimensions and d the embedment (ft). es_profile is either a constant Young’s modulus (psf) or a callable Es(depth_below_ footing_ft). C1 is the embedment correction 1 - 0.5*(q'/dq) >= 0.5 with q' = gamma*d the overburden at footing level; C2 the creep factor 1 + 0.2*log10(years/0.1). The strain-influence diagram peaks at Izp = 0.5 + 0.1*sqrt(dq/sigma'_vp).

civilpy.geotech.shallow_foundation.shape_factors(b: float, l: float, phi_deg: float, nq: float, nc: float) tuple[float, float, float][source]

De Beer / Vesic shape factors (sc, sq, sgamma) for an effective footing b by l (b is the smaller plan dimension). nq/nc are the bearing-capacity factors.

civilpy.geotech.shallow_foundation.stress_increase_2to1(q: float, b: float, l: float, z: float) float[source]

Vertical stress increase (same unit as q) at depth z below a b x l loaded area by the 2:1 (2 vertical : 1 horizontal) method: dsigma = q*B*L/((B+z)(L+z)).

civilpy.geotech.shallow_foundation.ultimate_bearing_capacity(b: float, l: float, d: float, gamma: float, phi_deg: float, c: float = 0.0, method: str = 'vesic', shape: bool = True, depth: bool = True, ecc_b: float = 0.0, ecc_l: float = 0.0, h: float = 0.0, v: float | None = None, water_table: float | None = None, gamma_sat: float | None = None) BearingCapacityResult[source]

General bearing-capacity equation (AASHTO LRFD 10.6.3.1.2):

q_ult = c*Nc*sc*dc*ic + q*Nq*sq*dq*iq + 0.5*gamma*B'*Ngamma*sg*dg*ig

b and l are the plan dimensions (ft, b <= l), d the embedment depth, gamma the soil unit weight (pcf), c the cohesion (psf). Eccentricities ecc_b/ecc_l (ft) trigger Meyerhof’s effective-width reduction B' = B - 2e. A horizontal load h with vertical v (lb) brings in the inclination factors. water_table (ft) with gamma_sat (pcf) adjusts the surcharge and self-weight terms.

civilpy.geotech.soil_profile module

Soil profiles: boring-log style layer columns and the total/pore/ effective vertical stress diagram every soils course draws.

Units: ft and pcf in, psf out.

Examples

>>> sp = SoilProfile([SoilLayer("Sand", 10, 115), SoilLayer("Clay", 15, 105)])
>>> sp.water_table = 10
>>> total, pore, eff = sp.stresses_at(25)
>>> round(total, 0), round(pore, 0), round(eff, 0)
(2725.0, 936.0, 1789.0)
class civilpy.geotech.soil_profile.SoilLayer(name, thickness, gamma, color=None)[source]

Bases: SoilLayer

One stratum: thickness ft of soil at total unit weight gamma pcf; color optional for the log plot.

class civilpy.geotech.soil_profile.SoilProfile(layers: list[SoilLayer], water_table: float | None = None)[source]

Bases: object

property depth: float
plot(ax=None, spt=None)[source]

Boring-log column with layer names; optional spt list of (depth, N) plotted alongside.

plot_stress_profile(ax=None, n: int = 300)[source]

Total stress, pore pressure, and effective stress vs depth.

stresses_at(z: float) tuple[float, float, float][source]

(total, pore, effective) vertical stress (psf) at depth z.

civilpy.geotech.spt module

SPT blow-count correlations: the derived-parameter engine that turns a Standard Penetration Test N value into the soil properties the downstream libraries need.

These are published, widely used empirical correlations. They are estimates only – approximate and scatter-prone – and should never replace laboratory testing where it is available; they exist so a boring log with nothing but blow counts can still seed a calculation.

Units are US customary: stresses in psf, unit weights in pcf, moduli in psi, angles in degrees. N arguments are field blow counts unless the name says n60 (energy-corrected) or n1_60 (energy- and overburden-corrected).

References

  • Liao & Whitman (1986) – overburden correction CN.

  • Skempton (1986) – N60 corrections and relative density.

  • Hatanaka & Uchida (1996) – friction angle from (N1)60.

  • Stroud (1974) – undrained shear strength from N.

  • Bowles, Foundation Analysis and Design, 5th ed. (1996) – elastic modulus from N.

civilpy.geotech.spt.PATM_PSF = 2000.0

Atmospheric pressure used to normalise overburden, psf (~1 tsf).

civilpy.geotech.spt.elastic_modulus_from_spt(n: float, soil_type: str = 'sand') float[source]

Drained Young’s modulus Es (psi) from N (Bowles 1996, Es = a (N + b) in kPa). soil_type selects the coefficients: "sand", "sand_saturated", "gravelly_sand", "silty_sand", or "clayey_sand".

civilpy.geotech.spt.elastic_modulus_from_su(su_psf: float, modulus_ratio: float = 300.0) float[source]

Undrained Young’s modulus Eu (psi) of a clay as modulus_ratio times the undrained shear strength: Eu = beta * Su. modulus_ratio beta ~ 150 (soft) to 600 (stiff, OC) clays; 300 is a common default.

civilpy.geotech.spt.friction_angle_from_n(n1_60_value: float) float[source]

Effective friction angle phi’ (degrees) of a sand from (N1)60 (Hatanaka & Uchida 1996): phi’ = sqrt(20 (N1)60) + 20.

civilpy.geotech.spt.n1_60(n60: float, sigma_v_eff_psf: float, cap: float = 1.7) float[source]

Energy- and overburden-corrected blow count (N1)60 = CN * N60.

civilpy.geotech.spt.overburden_correction(sigma_v_eff_psf: float, cap: float = 1.7) float[source]

Overburden normalisation factor CN (Liao & Whitman 1986): CN = sqrt(Pa / sigma’_v), capped at cap (1.7 typical, 2.0 sometimes used). sigma_v_eff_psf is the effective vertical stress at the test depth.

civilpy.geotech.spt.relative_density_from_n(n1_60_value: float, constant: float = 60.0) float[source]

Relative density Dr (fraction 0-1) of a sand from (N1)60 (Skempton 1986): Dr = sqrt((N1)60 / constant), clamped to 1.0.

civilpy.geotech.spt.undrained_shear_strength_from_n(n60: float, factor_psf: float = 92.0) float[source]

Undrained shear strength Su (psf) of a fine-grained soil from N60 (Stroud 1974): Su = f1 * N60. factor_psf f1 ~ 92 psf (4.4 kPa) is a representative value for insensitive clays; it ranges roughly 75-150 psf (3.5-7 kPa) with plasticity.

civilpy.geotech.spt.unit_weight_from_n(n: float, coarse: bool = True) float[source]

Rough total unit weight (pcf) from N when no laboratory value is available, after the Terzaghi-Peck consistency/density descriptions.

coarse True for sands/gravels (by relative density), False for clays/silts (by consistency). These are mid-range representative values, not a substitute for measured unit weights.

Module contents

Geotechnical engineering package.

Re-exports the boring-log data model (Borehole, samples, SPT results, gradations) and the DIGGS / PDF log parsers from civilpy.geotech.boring_io, plus quick lateral earth-pressure helpers (Rankine/Coulomb). Deeper analyses live in the submodules: spt (corrections and correlations), shallow_foundation / deep_foundation, axial_load_transfer, lateral_pile / lpile, soil_profile, lateral_earth, and culmanns.

civilpy.geotech.cande_adapter is intentionally not imported here so that importing this package does not pull in civilpy.structural.

civilpy.geotech.coulomb_active_pressure(unit_weight, height, friction_angle, wall_friction_angle, backfill_inclination, wall_inclination)[source]

Calculate active earth pressure against an abutment using the Coulomb method.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³ or lb/ft³) height (float): Height of the abutment (meters or feet) friction_angle (float): Internal friction angle of the soil (degrees) wall_friction_angle (float): Angle of wall friction (delta) (degrees) backfill_inclination (float): Angle of inclination of the backfill surface (theta) (degrees) wall_inclination (float): Inclination of the back side of the wall (beta) (degrees)

Returns: float: Active earth pressure (kN/m² or lb/ft²)

civilpy.geotech.coulomb_active_pressure_with_surcharge(unit_weight, height, friction_angle, wall_friction_angle, backfill_inclination, wall_inclination, surcharge_load)[source]

Calculate active earth pressure against an abutment using the Coulomb method with a surcharge load.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³ or lb/ft³) height (float): Height of the abutment (meters or feet) friction_angle (float): Internal friction angle of the soil (degrees) wall_friction_angle (float): Angle of wall friction (delta) (degrees) backfill_inclination (float): Angle of inclination of the backfill surface (theta) (degrees) wall_inclination (float): Inclination of the back side of the wall (beta) (degrees) surcharge_load (float): Surcharge load at the surface (kN/m² or lb/ft²)

Returns: float: Active earth pressure (kN/m² or lb/ft²)

civilpy.geotech.culmann_lateral_pressure(unit_weight, height, cohesion, friction_angle, wall_friction_angle, num_slices=100)[source]

Calculate horizontal lateral earth pressure using Culmann’s method.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³) height (float): Height of the wall (meters) cohesion (float): Cohesion of the soil (kPa) friction_angle (float): Internal friction angle of the soil (degrees) wall_friction_angle (float): Wall friction angle (degrees) num_slices (int): Number of slices for the graphical method

Returns: float: Horizontal lateral earth pressure (kPa)

civilpy.geotech.culmann_lateral_pressure_with_surcharge(unit_weight, height, cohesion, friction_angle, wall_friction_angle, surcharge_load, num_slices=100)[source]

Calculate horizontal lateral earth pressure using Culmann’s method including a live load surcharge.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³) height (float): Height of the wall (meters) cohesion (float): Cohesion of the soil (kPa) friction_angle (float): Internal friction angle of the soil (degrees) wall_friction_angle (float): Wall friction angle (degrees) surcharge_load (float): Live load surcharge at the surface (kPa) num_slices (int): Number of slices for the graphical method

Returns: float: Horizontal lateral earth pressure (kPa)

civilpy.geotech.rankine_active_pressure(unit_weight, height, friction_angle)[source]

Calculate active earth pressure against an abutment using the Rankine method.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³ or lb/ft³) height (float): Height of the abutment (meters or feet) friction_angle (float): Internal friction angle of the soil (degrees)

Returns: float: Active earth pressure (kN/m or lb/ft)

civilpy.geotech.rankine_active_pressure_with_surcharge(unit_weight, height, friction_angle, surcharge_load)[source]

Calculate active earth pressure against an abutment using the Rankine method with a surcharge load.

Parameters: unit_weight (float): Unit weight of the soil (kN/m³ or lb/ft³) height (float): Height of the abutment (meters or feet) friction_angle (float): Internal friction angle of the soil (degrees) surcharge_load (float): Surcharge load at the surface (kN/m² or lb/ft²)

Returns: float: Active earth pressure (kN/m² or lb/ft²)