Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Mohr circle for strains

Β© 2022 Exneyder A. Montoya-Araque, Daniel F. Ruiz and Universidad EAFIT.

This notebook can be interactively run in Google - Colab.

This notebook was developed following the theory presented in Ch. 1 - Book Mohr Circles, Stress Paths and Geotechnics (2nd Ed.) by Parry (2014).

Required modules and global setup for plotsΒΆ

import ast
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from ipywidgets import widgets as wgt
from IPython import get_ipython
from IPython.display import display

if 'google.colab' in str(get_ipython()):
    print('Running on CoLab. Installing the required modules...')
    from subprocess import run
    # run('pip install ipympl', shell=True);
    from google.colab import output
    output.enable_custom_widget_manager()
    
# Figures setup
# %matplotlib widget
mpl.rcParams.update({
    "font.family": "serif",
    "font.serif": ["Computer Modern Roman", "cmr", "cmr10", "DejaVu Serif"],  # or 
    "mathtext.fontset": "cm",  # Use Computer Modern fonts for math
    "axes.formatter.use_mathtext": True,  # Use mathtext for axis labels
    "axes.unicode_minus": False,   # Use standard minus sign instead of a unicode character
})

FuncionesΒΆ

def get_strain_state(πœ€_xx, πœ€_yy, πœ€_xy):
    c = 0.5 * (πœ€_xx + πœ€_yy)
    r = np.sqrt((πœ€_xx - c) ** 2 + πœ€_xy**2)
    πœ€_1 = r * np.cos(0) + c
    πœ€_3 = r * np.cos(np.pi) + c

    strain_state = {
        "πœ€_1": πœ€_1,
        "πœ€_3": πœ€_3,
        "πœ€_xx": πœ€_xx,
        "πœ€_yy": πœ€_yy,
        "πœ€_xy": πœ€_xy,
        "πœ€_vol": (πœ€_1 + πœ€_3),
        "0.5*𝛾_max": r,
        "r": r,
        "c": c
    }
    return strain_state

def get_xy_from_angle(angle, r, c):
    x, y = r * np.cos(2*np.deg2rad(angle)) + c, r * np.sin(2*np.deg2rad(angle))
    return x, y

def plot_mohr_circle(πœ€_xx, πœ€_yy, πœ€_xy, plot_pole=False, plot_plane=False, πœ”=10,
                     xlim=None, ylim=None, **kwargs):
    strain_state = get_strain_state(πœ€_xx, πœ€_yy, πœ€_xy)
    pole = (πœ€_xx, -1 * πœ€_xy)
    angles4circ = np.linspace(0, 2 * np.pi, 200)

    fig, ax = plt.subplots(ncols=1, nrows=1, figsize=kwargs.get('figsize'))
    ax.plot(strain_state['r'] * np.cos(angles4circ) + strain_state['c'],
            strain_state['r'] * np.sin(angles4circ), c="k")  # Mohr circle
    ax.axhline(y=0, c="k")

    params = {'ls': "", "fillstyle": 'none', "markeredgewidth": 2, "ms": 7}
    label = ("$\\varepsilon_{xx}=$" + f"{πœ€_xx:.2f}" + ",\n$\\varepsilon_{xy}=$" + f"{πœ€_xy:.2f}")
    ax.plot(πœ€_xx, πœ€_xy, c="C3", marker="s", label=label, **params)  # πœ€_xx, πœ€_xy
    label = ("$\\varepsilon_{yy}=$" + f"{πœ€_yy:.2f}" + ",\n$\\varepsilon_{yx}=$" + f"{πœ€_xy:.2f}")
    ax.plot(πœ€_yy, -1 * πœ€_xy, c="C4", marker="s", label=label, **params)  # πœ€_yy, (-)πœ€_xy
    ax.plot(strain_state['c'], 0, ls="", c="k", marker=(8, 2, 0), ms=10) # Mean strain (center)
    label = "$0.5\\gamma_\mathrm{max}=$" + f"{strain_state['r']:.2f}" # Max shear str (radius)
    ax.plot(strain_state['c'], strain_state['r'], c="C2", marker='v', label=label, **params)
    label = "$\\varepsilon_{1}=$" + f"{strain_state['πœ€_1']:.2f}"  # epsilon_1
    ax.plot(strain_state['πœ€_1'], 0, c="C0", marker= "o", label=label, **params)
    label = "$\\varepsilon_{3}=$" + f"{strain_state['πœ€_3']:.2f}"  # epsilon_3
    ax.plot(strain_state['πœ€_3'], 0, c="C1", marker= "o", label=label, **params)

    if plot_pole:  # Pole and stress on a plane
        ax.axvline(x=pole[0], c="C3", ls="-", lw=1.25)
        ax.axhline(y=pole[1], c="C4", ls="-", lw=1.25)
        ax.plot(*pole, ls="", c="k", marker=".", fillstyle='full', ms=7,
            label=f"$P\ ({pole[0]:.2f}, {pole[1]:.2f})$")
    if plot_plane:
        𝛽 = 0.5 * np.degrees(np.arctan2(2 * πœ€_xy, πœ€_yy - πœ€_xx))
        πœƒ = -(πœ” + 𝛽)
        πœ€_dir, πœ€_shr = get_xy_from_angle(πœƒ, strain_state['r'], strain_state['c'])
        ax.plot((strain_state['c'], πœ€_yy, πœ€_xx), (0, -πœ€_xy, -πœ€_xy), c="k", ls="--",
            lw=1.25, label="Plane $\\varepsilon_y$")
        label=f"Plane at $\\omega={πœ”:.1f}$" + \
            "$^{\\circ}\\circlearrowright$\nfrom Plane $\\varepsilon_y$"
        ax.plot((πœ€_dir, pole[0]), (πœ€_shr, pole[1]), c="C5", ls="--", lw=1.25, label=label)
        label = f"Plane at $2\\omega={2*πœ”:.1f}$" + \
            "$^{\\circ}\\circlearrowright$\nfrom Plane $\\varepsilon_y$"
        ax.plot((πœ€_dir, strain_state['c']), (πœ€_shr, 0), c="C6", ls="--", lw=1.25, label=label)
        label = ("Strains on the plane\n" + "$\\varepsilon=$" + f"{πœ€_dir:.2f}"
            + ", $0.5\\gamma=$" + f"{πœ€_shr:.2f}")
        ax.plot(πœ€_dir, πœ€_shr, ls="", c="k", marker=".", label=label)
        
    ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
    ax.grid(True, ls="--")
    ax.spines["bottom"].set_linewidth(1.5)
    ax.spines["left"].set_linewidth(1.5)
    ax.set_aspect("equal", anchor=None)
    ax.set(
        xlabel="Direct strain, $\\varepsilon$",
        ylabel="Shear strain, $0.5\\gamma$",
        xlim=xlim,
        ylim=ylim
    )
    return strain_state
def plot_zero_ext_comp_lines(π›Ώπœ€_h, π›Ώπœ€_v, plot_plane=False, πœ”=10, xlim=None,
                             ylim=None, **kwargs):
    π›Ώπœ€_1, π›Ώπœ€_3 = max(π›Ώπœ€_h, π›Ώπœ€_v), min(π›Ώπœ€_h, π›Ώπœ€_v)  # Principal strains

    def getlbl(π›Ώπœ€):
        lb = 'h' if π›Ώπœ€ == π›Ώπœ€_h else 'v'
        return '$\\delta\\varepsilon_\\mathrm{'+lb+'}=$'

    strain_state = get_strain_state(π›Ώπœ€_1, π›Ώπœ€_3, 0)
    angles4circ = np.linspace(0, 2 * np.pi, 200)
    pole = (π›Ώπœ€_h, 0)
    πœ“ = np.rad2deg(np.arcsin(-strain_state['c'] / (strain_state['r'])))

    fig, ax = plt.subplots(ncols=1, nrows=1, figsize=kwargs.get('figsize'))
    ax.plot(strain_state['r'] * np.cos(angles4circ) + strain_state['c'],
            strain_state['r'] * np.sin(angles4circ), c="k")  # Mohr circle
    params = {'ls': "", "fillstyle": 'none', "markeredgewidth": 1.75, "ms": 7}
    label = ("$\\delta\\varepsilon_1=$" + getlbl(π›Ώπœ€_1) + f"{π›Ώπœ€_1:.2f}")
    ax.plot(π›Ώπœ€_1, 0, c="C0", marker="o", label=label, **params)  # π›Ώπœ€_1
    label = ("$\delta\\varepsilon_3=$" + getlbl(π›Ώπœ€_3) + f"{π›Ώπœ€_3:.2f}")
    ax.plot(π›Ώπœ€_3, 0, c="C1", marker="o", label=label, **params)  # π›Ώπœ€_3
    ax.plot(strain_state['c'], 0, ls="", c="k", marker=(8, 2, 0), ms=10) # Mean strain (center)
    label = "$0.5\\delta\\gamma_\mathrm{max}=$" + f"{strain_state['r']:.2f}" # Max shear str (radius)
    ax.plot(strain_state['c'], strain_state['r'], c="C2", marker='v', label=label, **params)
    label = "$0.5\\delta\\varepsilon_\\mathrm{vol}=" + f"{strain_state['c']:.3f}$" + \
        f"\n$\\hookrightarrow \\psi={πœ“:.1f}$" + "$^{\circ}$"
    ax.plot((strain_state['c'], 0), (0, 0), c="grey", ls="-", lw=3, label=label)  # 𝛿v/2)
    # Zero extension lines
    𝛽 = 0.5 * np.degrees(np.arctan2(0, π›Ώπœ€_v - π›Ώπœ€_h))
    πœƒ_zero = np.rad2deg(0.5 * np.arccos(-strain_state['c'] / strain_state['r']))
    πœ€_dir, πœ€_shr = get_xy_from_angle(πœƒ_zero, strain_state['r'], strain_state['c'])
    ax.plot((πœ€_dir, π›Ώπœ€_h, πœ€_dir), (πœ€_shr, 0, -πœ€_shr), c="k", ls="--", lw=1.25,
        label="Zero direct strain planes\n($\\delta\\varepsilon=0$)")
    πœ€_dir, πœ€_shr = get_xy_from_angle(πœƒ_zero-90, strain_state['r'], strain_state['c'])
    ax.plot((πœ€_dir, π›Ώπœ€_h, πœ€_dir), (πœ€_shr, 0, -πœ€_shr), c="k", ls="-", lw=1.25,
        label="Zero extension lines")
    # Arbitrary plane
    if  plot_plane:
        ax.plot((π›Ώπœ€_v, π›Ώπœ€_h), (0, 0), c="C3", ls="--", lw=1.25,
                label="Plane $\\delta\\varepsilon_\\mathrm{v}$")
        πœƒ = -(πœ” + 𝛽)
        πœ€_dir, πœ€_shr = get_xy_from_angle(πœƒ, strain_state['r'], strain_state['c'])
        label=f"Plane at $\\omega={πœ”:.1f}$" + \
            "$^{\circ}\\circlearrowright$\nfrom Plane $\\delta\\varepsilon_1$"
        ax.plot((πœ€_dir, pole[0]), (πœ€_shr, pole[1]), c="C4", ls="--", lw=1.25, label=label)
        label = f"Plane at $2\\omega={2*πœ”:.1f}$" + \
                "$^{\circ}\\circlearrowright$\nfrom Plane $\\delta\\varepsilon_\\mathrm{v}$"
        ax.plot((πœ€_dir, strain_state['c']), (πœ€_shr, 0), c="C5", ls="--", lw=1.25, label=label)
        label = ("Strains on the plane\n" + "$\\varepsilon=$" + f"{πœ€_dir:.2f}"
                 + ", $0.5\\gamma=$" + f"{πœ€_shr:.2f}")
        ax.plot(πœ€_dir, πœ€_shr, ls="", c="k", marker="o", fillstyle='none', label=label)
    ax.plot(*pole, ls="", c="k", marker=".", fillstyle='full', ms=7, # Pole
            label=f"$P\ ({pole[0]:.2f}, {pole[1]:.2f})$")
    # Plot settings
    ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
    ax.grid(True, ls="--")
    ax.spines["bottom"].set_linewidth(1.5)
    ax.spines["left"].set_linewidth(1.5)
    ax.set_aspect("equal", anchor=None)
    ax.set(xlabel="$\\delta\\varepsilon$", ylabel="$\\delta0.5\delta\\gamma$",
        xlim=xlim, ylim=ylim)
    return

Ejemplo bΓ‘sico del Circulo de MohrΒΆ

# plot_mohr_circle(πœ€_xx=30, πœ€_yy=20, πœ€_xy=10)
plot_mohr_circle(πœ€_xx=-0.01, πœ€_yy=0.2, πœ€_xy=-0.2, plot_pole=True)
{'πœ€_1': 0.3208871399615304, 'πœ€_3': -0.13088713996153037, 'πœ€_xx': -0.01, 'πœ€_yy': 0.2, 'πœ€_xy': -0.2, 'πœ€_vol': 0.19000000000000003, '0.5*𝛾_max': 0.22588713996153037, 'r': 0.22588713996153037, 'c': 0.095}
<Figure size 640x480 with 1 Axes>
s, l = {'description_width': '60px'}, wgt.Layout(width='400px')
s_env, l_env = {'description_width': '60px'}, wgt.Layout(width='190px')
controls = {
    'Ξ΅_xx': wgt.FloatSlider(value=-0.1, min=-1, max=1, description="πœ€_xx", style=s, layout=l),
    'Ξ΅_yy': wgt.FloatSlider(value=0.2, min=-1, max=1, description="πœ€_yy", style=s, layout=l),
    'Ξ΅_xy': wgt.FloatSlider(value=-0.2, min=-1, max=1, description="πœ€_xy", style=s, layout=l),
    'plot_pole': wgt.Checkbox(value=False, description="Plot pole?", style=s, layout=l),
    'plot_plane': wgt.Checkbox(value=False, description="Plot a plane? β†’ ", style=s_env, layout=wgt.Layout(width='180px')),
    'Ο‰': wgt.FloatSlider(value=10, min=0, max=180, step=0.2, description="πœ”", style={'description_width': '10px'}, layout=wgt.Layout(width='220px')),
    'xlim': wgt.FloatRangeSlider(value=[-.3, .5], min=-1, max=1, step=.5, description='x-axis:', readout_format='.0f', style=s, layout=l),
    'ylim': wgt.FloatRangeSlider(value=[-.3, .3], min=-1, max=1, step=.5, description='y-axis:', readout_format='.0f', style=s, layout=l),
    'static_fig': wgt.Checkbox(value=True, description='Non-vector image (improve widget performance)', disabled=False, style=s, layout=l)
}
c_all = list(controls.values())
c_pln = [wgt.HBox(c_all[4:6])]
c = c_all[:4] + c_pln + c_all[6:]
fig = wgt.interactive_output(plot_mohr_circle, controls)
wgt.HBox((wgt.VBox(c), fig), layout=wgt.Layout(align_items='center'))
Loading...

Lineas de cero extensiΓ³n en el cΓ­rculo de MohrΒΆ

plot_zero_ext_comp_lines(π›Ώπœ€_h=-0.16, π›Ώπœ€_v=0.094, plot_plane=True, πœ”=25)
plot_zero_ext_comp_lines(π›Ώπœ€_h=0.16, π›Ώπœ€_v=-0.094, plot_plane=True, πœ”=25)
plot_zero_ext_comp_lines(π›Ώπœ€_h=-0.094, π›Ώπœ€_v=0.16, plot_plane=True, πœ”=25)
<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>
s, l = {'description_width': '60px'}, wgt.Layout(width='400px')
s_env, l_env = {'description_width': '60px'}, wgt.Layout(width='190px')
controls = {
    'δΡ_h': wgt.FloatSlider(value=-0.16, min=-1, max=1, step=.0001, description="π›Ώπœ€_h", readout_format='.4f', style=s, layout=l),
    'δΡ_v': wgt.FloatSlider(value=0.0942, min=-1, max=1, step=.0001, description="π›Ώπœ€_v", readout_format='.4f', style=s, layout=l),
    'plot_plane': wgt.Checkbox(value=False, description="Plot a plane? β†’ ", style=s_env, layout=wgt.Layout(width='180px')),
    'Ο‰': wgt.FloatSlider(value=10, min=0, max=180, step=1, description="πœ”", style={'description_width': '10px'}, layout=wgt.Layout(width='220px')),
    'xlim': wgt.FloatRangeSlider(value=[-.2, .2], min=-1, max=1, step=.02, description='x-axis:', readout_format='.2f', style=s, layout=l),
    'ylim': wgt.FloatRangeSlider(value=[-.15, .15], min=-1, max=1, step=.02, description='y-axis:', readout_format='.2f', style=s, layout=l),
    'static_fig': wgt.Checkbox(value=True, description='Non-vector image (improve widget performance)', disabled=False, style=s, layout=l)
}
c_all = list(controls.values())
c_pln = [wgt.HBox(c_all[2:4])]
c = c_all[:2] + c_pln + c_all[4:]
fig = wgt.interactive_output(plot_zero_ext_comp_lines, controls)
wgt.HBox((wgt.VBox(c), fig), layout=wgt.Layout(align_items='center'))
Loading...
ReferencesΒΆ
  1. Parry, R. (2014). Mohr Circles, Stress Paths and Geotechnics (2nd ed.). CRC Press. 10.1201/9781482264982