driven-pile 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ """driven-pile: long-term capacity of driven piles from the pile-driving log.
2
+
3
+ Each logged foot of driving
4
+ characterizes the soil at the toe once (friction angle, equivalent N1,60,
5
+ cyclic resistance), the pore pressure generated by later hammer blows sets
6
+ that foot's shaft resistance for the rest of the drive, and the end-of-drive
7
+ characterization with pore pressure dissipated gives the long-term capacity.
8
+ """
9
+
10
+ from .analysis import analyze
11
+ from .capacity import long_term_capacity
12
+ from .inputs import DriveLog, Hammer, Pile, SoilProfile, bpm_to_stroke, stroke_to_bpm
13
+ from .march import run_drive
14
+ from .montecarlo import monte_carlo
15
+ from .options import ModelOptions, MonteCarloOptions
16
+ from .preprocess import Target, prepare_target
17
+ from .results import Analysis, DriveResult, MonteCarloResult, TopPhiBand
18
+ from .top_segment import sweep_top_phi
19
+
20
+ __version__ = "0.1.0"
21
+
22
+ __all__ = [
23
+ "Analysis", "DriveLog", "DriveResult", "Hammer", "ModelOptions",
24
+ "MonteCarloOptions", "MonteCarloResult", "Pile", "SoilProfile", "Target",
25
+ "TopPhiBand", "analyze",
26
+ "bpm_to_stroke", "long_term_capacity", "monte_carlo", "prepare_target",
27
+ "run_drive", "stroke_to_bpm", "sweep_top_phi",
28
+ ]
@@ -0,0 +1,43 @@
1
+ """One-call analysis of a driving log."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .march import run_drive
6
+ from .montecarlo import monte_carlo
7
+ from .options import ModelOptions, MonteCarloOptions
8
+ from .preprocess import prepare_target
9
+ from .results import Analysis
10
+ from .top_segment import sweep_top_phi
11
+
12
+
13
+ def analyze(log, soil, options=None, mc_options=None, run_mc=False):
14
+ """Characterize the soil from a driving log and estimate long-term capacity.
15
+
16
+ Parameters
17
+ ----------
18
+ log : DriveLog
19
+ The driving record, with its pile and hammer.
20
+ soil : SoilProfile
21
+ Mudline, water table, unit weight and fines content.
22
+ options : ModelOptions, optional
23
+ Model parameters; defaults to the published values.
24
+ mc_options : MonteCarloOptions, optional
25
+ Monte Carlo settings, used when ``run_mc`` is True.
26
+ run_mc : bool, default False
27
+ Also run the Monte Carlo simulation.
28
+
29
+ Returns
30
+ -------
31
+ Analysis
32
+ The deterministic run uses the lowest admissible top-segment
33
+ friction angle.
34
+ """
35
+ options = options or ModelOptions()
36
+ target = prepare_target(log, soil, options)
37
+ band = sweep_top_phi(target, options)
38
+ drive = run_drive(target, options, top_phi=band.lo)
39
+ mc = None
40
+ if run_mc:
41
+ mc = monte_carlo(log, soil, options, mc_options or MonteCarloOptions(),
42
+ target=target, top_band=band)
43
+ return Analysis(drive=drive, top_band=band, mc=mc)
driven_pile/bearing.py ADDED
@@ -0,0 +1,148 @@
1
+ """Toe bearing in sand: Vesic cavity expansion with a stress-dependent rigidity
2
+ index, and its inversion for the friction angle."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import numpy as np
7
+ from scipy.optimize import brentq
8
+
9
+ from .constants import ABOVE_CEILING, BELOW_FLOOR, NONFINITE, OK, P_ATM
10
+
11
+ _GRID_POINTS = 512
12
+
13
+
14
+ def nq_vesic(phi, irr, k0=None):
15
+ """Vesic bearing capacity factor on vertical effective stress.
16
+
17
+ Parameters
18
+ ----------
19
+ phi : array_like
20
+ Friction angle, deg.
21
+ irr : array_like
22
+ Reduced rigidity index.
23
+ k0 : array_like, optional
24
+ At-rest earth pressure coefficient; ``1 - sin(phi)`` by default.
25
+
26
+ Returns
27
+ -------
28
+ ndarray
29
+ ``N_q* = N_sigma (1 + 2 K0) / 3`` with
30
+ ``N_sigma = 3 / (3 - sin phi) exp((pi/2 - phi) tan phi)
31
+ tan^2(45 + phi/2) Irr^(4 sin phi / (3 (1 + sin phi)))``.
32
+
33
+ References
34
+ ----------
35
+ Vesic (1977).
36
+ """
37
+ p = np.radians(np.asarray(phi, dtype=float))
38
+ sin_p = np.sin(p)
39
+ if k0 is None:
40
+ k0 = 1.0 - sin_p
41
+ n_sigma = (
42
+ (3.0 / (3.0 - sin_p))
43
+ * np.exp((np.pi / 2.0 - p) * np.tan(p))
44
+ * np.tan(np.pi / 4.0 + p / 2.0) ** 2
45
+ * np.asarray(irr, dtype=float) ** (4.0 * sin_p / (3.0 * (1.0 + sin_p)))
46
+ )
47
+ return n_sigma * (1.0 + 2.0 * k0) / 3.0
48
+
49
+
50
+ def rigidity_index(phi, sigma_v, options):
51
+ """Rigidity index from a stress-dependent shear modulus.
52
+
53
+ Parameters
54
+ ----------
55
+ phi : array_like
56
+ Friction angle, deg.
57
+ sigma_v : array_like
58
+ Vertical effective stress, ksf.
59
+ options : ModelOptions
60
+ Supplies ``g_ratio``, ``k2_lo``, ``k2_hi``, ``phi_lo``, ``phi_hi``
61
+ and ``irr_bounds``.
62
+
63
+ Returns
64
+ -------
65
+ ndarray
66
+ ``I_r = g_ratio G_max / (sigma'_m tan phi)`` clamped to
67
+ ``irr_bounds``, with ``sigma'_m = (1 + 2 K0) / 3 sigma'_v`` and
68
+ ``G_max = 21.7 K2 Pa sqrt(sigma'_m / Pa)``.
69
+
70
+ References
71
+ ----------
72
+ Seed and Idriss (1970).
73
+ """
74
+ phi = np.asarray(phi, dtype=float)
75
+ p = np.radians(phi)
76
+ k0 = 1.0 - np.sin(p)
77
+ sig_m = np.maximum((1.0 + 2.0 * k0) / 3.0 * np.asarray(sigma_v, dtype=float), 1e-3)
78
+ k2 = np.interp(phi, [options.phi_lo, options.phi_hi], [options.k2_lo, options.k2_hi])
79
+ g_max = 21.7 * k2 * P_ATM * np.sqrt(sig_m / P_ATM)
80
+ ir = options.g_ratio * g_max / (sig_m * np.tan(p))
81
+ return np.clip(ir, *options.irr_bounds)
82
+
83
+
84
+ def toe_bearing(sigma_v, phi, options):
85
+ """Unit toe resistance ``q_p = N_q*(phi, I_r) sigma'_v``, ksf."""
86
+ irr = rigidity_index(phi, sigma_v, options)
87
+ return np.asarray(sigma_v, dtype=float) * nq_vesic(phi, irr)
88
+
89
+
90
+ def phi_from_toe_bearing(q_needed, sigma_v, options):
91
+ """Friction angle whose toe bearing on ``sigma_v`` equals ``q_needed``.
92
+
93
+ Parameters
94
+ ----------
95
+ q_needed : float
96
+ Required unit toe resistance, ksf.
97
+ sigma_v : float
98
+ Vertical effective stress at the toe, ksf.
99
+ options : ModelOptions
100
+ Supplies the friction angle bounds and rigidity parameters.
101
+
102
+ Returns
103
+ -------
104
+ phi : float
105
+ Friction angle, deg, held at a bound when the requirement lies
106
+ outside the attainable range; NaN when ``q_needed`` is not finite.
107
+ reason : str
108
+ One of the reason codes in `driven_pile.constants`.
109
+ """
110
+ lo, hi = options.phi_lo, options.phi_hi
111
+ if not np.isfinite(q_needed):
112
+ return np.nan, NONFINITE
113
+ if sigma_v <= 0:
114
+ return lo, BELOW_FLOOR
115
+ if q_needed <= toe_bearing(sigma_v, lo, options):
116
+ return lo, BELOW_FLOOR
117
+ if q_needed >= toe_bearing(sigma_v, hi, options):
118
+ return hi, ABOVE_CEILING
119
+ phi = brentq(lambda p: float(toe_bearing(sigma_v, p, options)) - q_needed, lo, hi)
120
+ return phi, OK
121
+
122
+
123
+ def phi_from_toe_bearing_grid(q_needed, sigma_v, options):
124
+ """Friction angle from toe bearing by interpolation on a fixed grid.
125
+
126
+ Parameters
127
+ ----------
128
+ q_needed : float or array_like
129
+ Required unit toe resistance, ksf.
130
+ sigma_v : float or array_like
131
+ Vertical effective stress at the toe, ksf.
132
+ options : ModelOptions
133
+ Supplies the friction angle bounds and rigidity parameters.
134
+
135
+ Returns
136
+ -------
137
+ float or ndarray
138
+ Friction angle, deg, clamped to the bounds. Faster than
139
+ `phi_from_toe_bearing` when evaluated many times.
140
+ """
141
+ grid = np.linspace(options.phi_lo, options.phi_hi, _GRID_POINTS)
142
+ sig = np.atleast_1d(np.asarray(sigma_v, dtype=float))
143
+ q = np.broadcast_to(np.atleast_1d(np.asarray(q_needed, dtype=float)), sig.shape)
144
+ out = np.empty_like(sig)
145
+ for k, (s_k, q_k) in enumerate(zip(sig, q)):
146
+ qp = toe_bearing(max(s_k, 1e-9), grid, options)
147
+ out[k] = np.interp(q_k, qp, grid)
148
+ return out if np.ndim(sigma_v) else float(out[0])
@@ -0,0 +1,73 @@
1
+ """Long-term capacity from the end-of-drive characterization."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ from .bearing import toe_bearing
8
+ from .constants import FOOT_INCREMENT
9
+
10
+
11
+ def shaft_long_term(fs_ltc, pile):
12
+ """Long-term shaft resistance, kips.
13
+
14
+ Parameters
15
+ ----------
16
+ fs_ltc : array_like
17
+ Unit shaft resistance per foot after pore-pressure dissipation, ksf.
18
+ pile : Pile
19
+ Supplies the perimeter.
20
+ """
21
+ fs = np.asarray(fs_ltc, dtype=float)
22
+ return float(np.nansum(fs) * pile.perimeter * FOOT_INCREMENT)
23
+
24
+
25
+ def toe_end_of_drive(phi, sigma_v0, ru_toe, residual, pile, options):
26
+ """Toe resistance at the end of the drive, kips.
27
+
28
+ Parameters
29
+ ----------
30
+ phi : float
31
+ Friction angle of the final foot, deg.
32
+ sigma_v0 : float
33
+ Static vertical effective stress at the toe, ksf.
34
+ ru_toe : float
35
+ Pore-pressure ratio applied to the toe stress.
36
+ residual : float
37
+ Modeled minus target capacity at the final reconciled foot, kips;
38
+ subtracted from the toe so the end-of-drive total matches the log.
39
+ pile : Pile
40
+ Supplies the toe area.
41
+ options : ModelOptions
42
+ Rigidity parameters.
43
+
44
+ Returns
45
+ -------
46
+ float
47
+ Vesic bearing on the reduced stress ``(1 - ru_toe) sigma'v0``, less
48
+ the residual, floored at zero. No toe setup is modeled.
49
+ """
50
+ if not np.isfinite(phi):
51
+ return 0.0
52
+ qp = float(toe_bearing(sigma_v0 * (1.0 - ru_toe), phi, options)) * pile.area
53
+ return max(qp - residual, 0.0)
54
+
55
+
56
+ def long_term_capacity(result):
57
+ """Long-term shaft and toe resistance of a `DriveResult`.
58
+
59
+ Parameters
60
+ ----------
61
+ result : DriveResult
62
+
63
+ Returns
64
+ -------
65
+ shaft, toe : float
66
+ Kips. The toe is its end-of-drive value.
67
+ """
68
+ shaft = shaft_long_term(result.fs_ltc, result.pile)
69
+ m = np.isfinite(result.target) & np.isfinite(result.predicted)
70
+ residual = float(result.predicted[m][-1] - result.target[m][-1]) if m.any() else 0.0
71
+ toe = toe_end_of_drive(result.phi[-1], result.sigma_v0[-1], result.ru_toe[-1],
72
+ residual, result.pile, result.options)
73
+ return shaft, toe
@@ -0,0 +1,24 @@
1
+ """Physical constants and the per-foot reason codes shared across modules."""
2
+
3
+ GAMMA_WATER = 0.0624
4
+ """Unit weight of water, ksf/ft."""
5
+
6
+ P_ATM = 2.116
7
+ """Atmospheric pressure, ksf."""
8
+
9
+ G_FT_S2 = 32.2
10
+ """Gravitational acceleration, ft/s^2."""
11
+
12
+ FOOT_INCREMENT = 1.0
13
+ """Length of one analysis increment, ft."""
14
+
15
+ OK = "ok"
16
+ ABOVE_CEILING = "above_ceiling"
17
+ BELOW_FLOOR = "below_floor"
18
+ NONFINITE = "nonfinite"
19
+ TOP_SEGMENT = "top_segment"
20
+
21
+ LIQ_BEFORE = "before"
22
+ LIQ_DURING = "during"
23
+ LIQ_AFTER = "after"
24
+ LIQ_NEVER = ""
@@ -0,0 +1,61 @@
1
+ """Dynamic capacity formula applied to the driving log."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+
8
+ def elastic_set(stroke, ram_weight, pile):
9
+ """Elastic compression term of the Danish formula.
10
+
11
+ Parameters
12
+ ----------
13
+ stroke : array_like
14
+ Hammer stroke, ft.
15
+ ram_weight : float
16
+ Ram weight, kips.
17
+ pile : Pile
18
+ Pile geometry and modulus.
19
+
20
+ Returns
21
+ -------
22
+ ndarray
23
+ ``s0 = sqrt(W h L / (2 A E))``, ft.
24
+ """
25
+ stroke = np.asarray(stroke, dtype=float)
26
+ return np.sqrt(ram_weight * stroke * pile.length / (2.0 * pile.area * pile.modulus))
27
+
28
+
29
+ def danish_capacity(bpf, stroke, ram_weight, pile, c1=0.45, c2=0.0):
30
+ """Capacity at the time of driving from the recalibrated Danish formula.
31
+
32
+ Parameters
33
+ ----------
34
+ bpf : array_like
35
+ Blows per foot.
36
+ stroke : array_like
37
+ Hammer stroke, ft.
38
+ ram_weight : float
39
+ Ram weight, kips.
40
+ pile : Pile
41
+ Pile geometry and modulus.
42
+ c1, c2 : float
43
+ Multiplicative and additive (kips) recalibration coefficients.
44
+
45
+ Returns
46
+ -------
47
+ ndarray
48
+ ``c1 * W h / (s + s0) + c2``, kips, with the set per blow
49
+ ``s = 1 / bpf`` ft.
50
+
51
+ References
52
+ ----------
53
+ Sorensen and Hansen (1957); Reddy and Stuedlein (2013), Puget Sound
54
+ recalibration with unadjusted hammer energy.
55
+ """
56
+ bpf = np.asarray(bpf, dtype=float)
57
+ stroke = np.asarray(stroke, dtype=float)
58
+ with np.errstate(divide="ignore", invalid="ignore"):
59
+ s = 1.0 / bpf
60
+ q = ram_weight * stroke / (s + elastic_set(stroke, ram_weight, pile))
61
+ return c1 * q + c2