Skip to content

Effective stress

Terzaghi's principle — the cornerstone of all soil mechanics:

\[ \boxed{\;\sigma' = \sigma - u\;} \]

The module's stress functions are deliberately thin wrappers over this rule, so you can compose them however your problem requires.

Quick example

Python
import geoeq as ge

# Layered total stress
ge.total_stress([17, 19, 20], [2, 3, 5])     # 191 kPa

# Hydrostatic pore pressure
ge.pore_pressure(5.0, z_w=2.0)               # 29.43 kPa
ge.pore_pressure([0, 2, 5, 10], z_w=2)       # vectorised

# Terzaghi effective stress
ge.effective_stress(154.0, 58.86)            # 95.14 kPa

For multi-layer integration, prefer the SoilProfile object — it handles the bookkeeping of which layer is above / below the water table for you.

Capillary rise

Python
ge.capillary_rise(D10=0.05, e=0.7)           # 0.57 m for a fine sand

Uses the Hazen-type estimate \(h_c = C / (e \, D_{10}^{\text{cm}})\) with \(C = 0.2\) by default. Reference: Das (2010) Eq. 5.8.

API reference

total_stress

Python
total_stress(gamma: Union[float, Sequence[float]], depth: Union[float, Sequence[float]]) -> float

Total vertical stress sigma_v = sum(gamma_i * H_i).

PARAMETER DESCRIPTION
gamma

Unit weight(s) of each layer (kN/m^3).

TYPE: float or sequence

depth

Either a single depth (with scalar gamma) -- returns gamma*depth -- or layer thicknesses matching gamma -- returns sum(gamma_i * H_i).

TYPE: float or sequence

RETURNS DESCRIPTION
sigma

Total vertical stress (kPa).

TYPE: float

Reference

Das (2010) Eq. 5.1; Terzaghi (1943).

Source code in geoeq/design/stress.py
Python
def total_stress(
    gamma: Union[float, Sequence[float]],
    depth: Union[float, Sequence[float]],
) -> float:
    """Total vertical stress sigma_v = sum(gamma_i * H_i).

    Parameters
    ----------
    gamma : float or sequence
        Unit weight(s) of each layer (kN/m^3).
    depth : float or sequence
        Either a single depth (with scalar gamma) -- returns gamma*depth --
        or layer thicknesses matching ``gamma`` -- returns sum(gamma_i * H_i).

    Returns
    -------
    sigma : float
        Total vertical stress (kPa).

    Reference
    ---------
    Das (2010) Eq. 5.1; Terzaghi (1943).
    """
    g = np.atleast_1d(np.asarray(gamma, dtype=float))
    d = np.atleast_1d(np.asarray(depth, dtype=float))
    check_positive(g, "gamma")
    check_non_negative(d, "depth")
    if g.size == 1 and d.size == 1:
        return float(g[0] * d[0])
    if g.size != d.size:
        raise ValueError(
            "gamma and depth must have equal length (one entry per layer).")
    return float(np.sum(g * d))

pore_pressure

Python
pore_pressure(z: Union[float, Iterable[float]], z_w: float = 0.0, gamma_w: float = GAMMA_WATER) -> Union[float, np.ndarray]

Hydrostatic pore pressure u = gamma_w * (z - z_w), clipped at 0.

PARAMETER DESCRIPTION
z

Depth(s) of interest (m, positive downward).

TYPE: float or array

z_w

Depth of the water table (m). Default 0 (water table at surface).

TYPE: float DEFAULT: 0.0

gamma_w

Unit weight of water (kN/m^3). Default 9.81.

TYPE: float DEFAULT: GAMMA_WATER

RETURNS DESCRIPTION
u

Pore pressure (kPa). Zero above the water table.

TYPE: float or array

Reference

Das (2010) Eq. 5.2.

Source code in geoeq/design/stress.py
Python
def pore_pressure(
    z: Union[float, Iterable[float]],
    z_w: float = 0.0,
    gamma_w: float = GAMMA_WATER,
) -> Union[float, np.ndarray]:
    """Hydrostatic pore pressure u = gamma_w * (z - z_w), clipped at 0.

    Parameters
    ----------
    z : float or array
        Depth(s) of interest (m, positive downward).
    z_w : float
        Depth of the water table (m). Default 0 (water table at surface).
    gamma_w : float
        Unit weight of water (kN/m^3). Default 9.81.

    Returns
    -------
    u : float or array
        Pore pressure (kPa). Zero above the water table.

    Reference
    ---------
    Das (2010) Eq. 5.2.
    """
    check_positive(gamma_w, "gamma_w")
    z_arr = np.asarray(z, dtype=float)
    u = gamma_w * np.maximum(0.0, z_arr - z_w)
    return float(u) if u.ndim == 0 else u

effective_stress

Python
effective_stress(sigma: Union[float, ndarray], u: Union[float, ndarray]) -> Union[float, np.ndarray]

Terzaghi effective stress sigma' = sigma - u (kPa).

Reference

Terzaghi (1943); Das (2010) Eq. 5.5.

Source code in geoeq/design/stress.py
Python
def effective_stress(
    sigma: Union[float, np.ndarray],
    u: Union[float, np.ndarray],
) -> Union[float, np.ndarray]:
    """Terzaghi effective stress sigma' = sigma - u (kPa).

    Reference
    ---------
    Terzaghi (1943); Das (2010) Eq. 5.5.
    """
    sigma = np.asarray(sigma, dtype=float)
    u = np.asarray(u, dtype=float)
    res = sigma - u
    return float(res) if res.ndim == 0 else res

capillary_rise

Python
capillary_rise(D10: float, e: float, C: float = 0.2) -> float

Capillary rise height in soil (Hazen-type estimate).

h_c [cm] = C / (e * D10 [cm])

PARAMETER DESCRIPTION
D10

Effective grain size, the 10% passing diameter (mm).

TYPE: float

e

Void ratio (-).

TYPE: float

C

Empirical constant; 0.1 < C < 0.5 typical. Default 0.2.

TYPE: float DEFAULT: 0.2

RETURNS DESCRIPTION
h_c

Capillary rise (m).

TYPE: float

Reference

Hazen (1930); Das (2010) Eq. 5.8.

Source code in geoeq/design/stress.py
Python
def capillary_rise(D10: float, e: float, C: float = 0.2) -> float:
    """Capillary rise height in soil (Hazen-type estimate).

    h_c [cm] = C / (e * D10 [cm])

    Parameters
    ----------
    D10 : float
        Effective grain size, the 10% passing diameter (mm).
    e : float
        Void ratio (-).
    C : float
        Empirical constant; 0.1 < C < 0.5 typical. Default 0.2.

    Returns
    -------
    h_c : float
        Capillary rise (m).

    Reference
    ---------
    Hazen (1930); Das (2010) Eq. 5.8.
    """
    check_positive(D10, "D10")
    check_positive(e, "e")
    D10_cm = D10 / 10.0  # mm to cm
    h_c_cm = C / (e * D10_cm)
    return h_c_cm / 100.0  # to m

stress_plot

Python
stress_plot(profile, dz: float = 0.1, **kwargs)

Plot total, pore, and effective stress vs depth.

Delegates to profile.plot(). See SoilProfile.plot.

Source code in geoeq/design/stress.py
Python
def stress_plot(profile, dz: float = 0.1, **kwargs):
    """Plot total, pore, and effective stress vs depth.

    Delegates to ``profile.plot()``. See ``SoilProfile.plot``.
    """
    return profile.plot(dz=dz, **kwargs)