- numpy - scipy - panel==0.13.1 - matplotlib
import panel as pn import numpy as np import scipy.integrate from matplotlib.figure import Figure from bokeh.models.formatters import PrintfTickFormatter current_x = None current_tau = None current_gamma = None x_list = [] tau_list = [] gamma_list = [] def calc_tau(gamma): Ga = 65500 gamma_y = 0.09 # the yield strain G_final = 1 # a very small slope for the upper part of the curve sign = np.sign(gamma) if np.abs(gamma) <= gamma_y: tau_unsigned = Ga * np.abs(gamma) else: tau_unsigned = Ga * gamma_y + \ G_final * (np.abs(gamma) - gamma_y) return sign * tau_unsigned calc_tau_vec = np.vectorize(calc_tau) def model(t1, t2, ta, L, P_A): E1 = 10.5e6 / (1 - 0.33**2) E2 = 10.5e6 / (1 - 0.33**2) Nend = P_A * L def ode(x, y): b = (1. / (E1 * t1) + 1. / (E2 * t2)) / ta return np.row_stack(( calc_tau_vec(y[1, :]) * b, y[0, :] )) def bc(ya, yb): return np.array([ ya[0] - 1. / ta * (-Nend / (E2 * t2)), yb[0] - 1. / ta * (Nend / (E1 * t1)) ]) res = scipy.integrate.solve_bvp( ode, bc, x = np.linspace(0, L, num=50), y = np.zeros((2, 50)) ) x = res.x gamma = res.y[1,:] tau = calc_tau_vec(gamma) return x, gamma, tau t1_input = pn.widgets.FloatSlider(name="Upper Adherend Thicknes [in]", start=0.03, end=0.25, step=0.01, value=0.06) t2_input = pn.widgets.FloatSlider(name="Lower Adherend Thickness [in]", start=0.03, end=0.25, step=0.01, value=0.06) ta_input = pn.widgets.FloatSlider(name="Adhesive Thickness [in]", start=0.002, end=0.020, step=0.001, value=0.005, format=PrintfTickFormatter(format='%.3f')) L_input = pn.widgets.FloatSlider(name="Overlap Length [in]", start=0.2, end=2.0, step=0.1, value=0.5) P_A_input = pn.widgets.FloatSlider(name="Load/Area (P/A) [lbf/in^2]", start=100, end=5850, step=10, value=5500) snapshotButton = pn.widgets.Button(name="Take Snapshot", width=300) clearButton = pn.widgets.Button(name="Clear All Snapshots", width=300) fig_stress_strain = Figure(figsize=(3, 2)) stress_strain_output = pn.pane.Matplotlib(fig_stress_strain, dpi=144) fig_stress = Figure(figsize=(5, 4)) stress_output = pn.pane.Matplotlib(fig_stress, dpi=144) fig_strain = Figure(figsize=(5, 4)) strain_output = pn.pane.Matplotlib(fig_strain, dpi=144) def draw_stress_strain(): fig_stress_strain.clear() ax0 = fig_stress_strain.subplots() ax0.clear() strain = np.linspace(0, 0.3, num=100) stress = calc_tau_vec(strain) ax0.plot(strain, stress) ax0.grid() ax0.set_title("Adhesive Stress-Strain Curve") ax0.set_xlabel("Shear Strain, $\\gamma$") ax0.set_ylabel("Shear Stress, $\\tau$") fig_stress_strain.tight_layout(pad=3) stress_strain_output.object = fig_stress_strain def plot_stress(x, tau): global current_x, current_gamma, current_tau global x_list, tau_list, gamma_list fig_stress.clear() ax0 = fig_stress.subplots() ax0.clear() for ii, (x_i, tau_i) in enumerate(zip(x_list, tau_list)): ax0.plot(x_i, tau_i, label=f"Snapshot {ii + 1}") ax0.plot(x, tau) ax0.grid() ax0.set_title("Adhesive Shear Stress") ax0.set_xlabel("x") ax0.set_ylabel("Shear Stress, $\\tau$") fig_stress.tight_layout(pad=3) if len(x_list) > 0: fig_stress.legend() stress_output.object = fig_stress def plot_strain(x, gamma): global current_x, current_gamma, current_tau global x_list, tau_list, gamma_list fig_strain.clear() ax0 = fig_strain.subplots() ax0.clear() for ii, (x_i, gamma_i) in enumerate(zip(x_list, gamma_list)): ax0.plot(x_i, gamma_i, label=f"Snapshot {ii + 1}") ax0.plot(x, gamma) ax0.grid() ax0.set_title("Adhesive Shear Strain") ax0.set_xlabel("x") ax0.set_ylabel("Shear Strain, $\\gamma$") fig_strain.tight_layout(pad=3) if len(x_list) > 0: fig_strain.legend() strain_output.object = fig_strain def update(obj): global current_x, current_gamma, current_tau global x_list, tau_list, gamma_list x, gamma, tau = model( t1_input.value, t2_input.value, ta_input.value, L_input.value, P_A_input.value ) current_x = x - L_input.value / 2 current_gamma = gamma current_tau = tau plot_stress(current_x, current_tau) plot_strain(current_x, current_gamma) def takeSnapshot(event): global current_x, current_gamma, current_tau global x_list, tau_list, gamma_list if current_x is not None and current_tau is not None and current_gamma is not None: x_list.append(current_x) tau_list.append(current_tau) gamma_list.append(current_gamma) def clearSnapshot(event): global current_x, current_gamma, current_tau global x_list, tau_list, gamma_list x_list = [] tau_list = [] gamma_list = [] plot_stress(current_x, current_tau) plot_strain(current_x, current_gamma) t1_input.param.watch(update, "value_throttled") t2_input.param.watch(update, "value_throttled") ta_input.param.watch(update, "value_throttled") L_input.param.watch(update, "value_throttled") P_A_input.param.watch(update, "value_throttled") snapshotButton.on_click(takeSnapshot) clearButton.on_click(clearSnapshot) draw_stress_strain() update(None) pn.Column( pn.FlexBox(*[t1_input, t2_input, ta_input, L_input, P_A_input]), pn.Row(snapshotButton, clearButton), pn.FlexBox(*[stress_output, strain_output]), fig_stress_strain ).servable(target='lap_shear_div');