Skip to content

cpt_layering

sjbrandenberg edited this page Dec 5, 2024 · 17 revisions

cpt_layering(*args)

A function that uses the agglomerative clustering algorithm by Hudson et al. (2023) to automatically identify spatially contiguous soil layers with similar qc1Ncs and Ic values.

Citation

Hudson, K. S., Ulmer, K., Zimmaro, P., Kramer, S. L., Stewart, J. P., and Brandenberg, S. J. (2023). "Unsupervised Machine Learning for Detecting Soil Layer Boundaries from Cone Penetration Test Data." Earthquake Engineering and Structural Dynamics, 52(11). link

Parameters

argument format description
qc1Ncs Numpy array, dtype=float overburden- and fines-corrected cone tip resistance
Ic Numpy array, dtype=float soil behavior type index
depth Numpy array, dtype=float depth to cpt measurement point
dGWT float depth to groundwater table
<num_layers> integer number of layers. optional. default = None.
<tknob> float constant used to define layer thickness parameter in cost function. optional. default = 0.5

Note

arguments in <brackets> are optional. If num_layers = None, the optimal number of layers is selected automatically based on a cost function that balances the distortion score with the desired layer thickness specified by the tknob parameter.

Returns

argument format description
ztop Numpy array, dtype=float depth to top of each layer
zbot Numpy array, dtype=float depth to bottom of each layer
qc1Ncs_lay Numpy array, dtype=float qc1Ncs values for each layer
Ic_lay float Ic values for each layer

Example

import numpy as np
import json
import pandas as pd
import requests
import io
import matplotlib.pyplot as plt
import ngl_tools.smt as smt

url = 'https://uclageo.com/coastal_database/conePenetrationTests'
headers = {'User-Agent':'XY', 'Accept':'application/json'}
r = requests.get(url,headers=headers)
cpt_df = pd.read_json(io.StringIO(r.text))
data = cpt_df['data'].values
dGWT = cpt_df['groundwater_measured'].values[0]
cpt_dict = json.loads(cpt_df.data.values[0])
depth = np.asarray(cpt_dict['depth'])
qc = np.asarray(cpt_dict['qc'])*1000
fs = np.asarray(cpt_dict['fs'])*1000
sigmav = 19 * depth
u = (depth - dGWT) * 9.81
u[u<0] = 0
sigmavp = sigmav - u
depth, qt_inv, fs_inv = smt.cpt_inverse_filter(qt=qc, z=depth, fs=fs, sigmav=sigmav, sigmavp=sigmavp)
Ic, Qtn, Fr = smt.get_Ic_Qtn_Fr(qc, fs, sigmav, sigmavp)
Ic_inv, Qtn_inv, Fr_inv = smt.get_Ic_Qtn_Fr(qt_inv, fs_inv, sigmav, sigmavp)
FC = smt.get_FC_from_Ic(Ic_inv, 0.0)
qc1N, qc1Ncs = smt.get_qc1N_qc1Ncs(qc, fs, sigmav, sigmavp, FC)
qc1N_inv, qc1Ncs_inv = smt.get_qc1N_qc1Ncs(qt_inv, fs_inv, sigmav, sigmavp, FC)
ztop, zbot, qc1Ncs_lay, Ic_lay = smt.cpt_layering(qc1Ncs_inv, Ic_inv, depth, dGWT)
fig, ax = plt.subplots(ncols=4, sharey='row')

ax[0].plot(qc, depth)
ax[0].plot(qt_inv, depth)
ax[1].plot(fs, depth)
ax[1].plot(fs_inv, depth)
ax[2].plot(Ic, depth)
ax[2].plot(Ic_inv, depth)
ax[3].plot(qc1Ncs, depth)
ax[3].plot(qc1Ncs_inv, depth)
ax[2].axvspan(1,1.31,alpha=0.3,color='darkorange')
ax[2].axvspan(1.31,2.05,alpha=0.3,color='peru')
ax[2].axvspan(2.05,2.6,alpha=0.3,color='palegreen')
ax[2].axvspan(2.6,2.95,alpha=0.3,color='mediumaquamarine')
ax[2].axvspan(2.95,3.6,alpha=0.3,color='navy')
ax[2].axvspan(3.6,4.0,alpha=0.3,color='saddlebrown')
ax[0].set_ylabel('depth [m]')
ax[0].set_xlabel(r'$q_c$ [kPa]')
ax[1].set_xlabel(r'$f_s$ [kPa]')
ax[2].set_xlabel(r'$I_c$ [-]')
ax[3].set_xlabel(r'$q_{c1Ncs}$ [-]')
for a in ax:
    a.grid(True, alpha=0.5)
ax[0].invert_yaxis()
ax[2].hlines(ztop,1,4, color='black', linewidth=0.5)
ax[2].hlines(zbot,1,4, color='black', linewidth=0.5)
ax[3].hlines(ztop,0,400, color='black', linewidth=0.5)
ax[3].hlines(zbot,0,400, color='black', linewidth=0.5)
ax[2].set_xlim(1,4)

Clone this wiki locally