-
Notifications
You must be signed in to change notification settings - Fork 286
Geo/soil test direct shear #13566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Geo/soil test direct shear #13566
Changes from 34 commits
4393d82
6eec8ca
010c9c7
12bd389
431340f
35b1522
5713ceb
c5d6eea
54f53d0
6319909
92d4d9d
b35a3c8
475cb9a
c671ba1
d8d0643
45edbd8
3ad38ec
b4c1c26
5f2a84f
19668e4
52e51ab
4fa31a0
c806610
122ce10
c6be8dd
4eb9313
f47e3c0
f9423f0
7b9331f
9d26b86
92bca78
96cf1c9
0d79b13
015e58d
76b88e6
6270054
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
rfaasse marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,7 @@ def update_maximum_strain(self, maximum_strain): | |
| replacer = self._replacer_factory(prescribed_displacement) | ||
| new_text, count = re.subn(pattern, replacer, self.raw_text) | ||
| if count == 0: | ||
| log_message("Could not update maximum strain.", "Warning") | ||
| log_message("Could not update maximum strain.", "warn") | ||
| else: | ||
| self.raw_text = new_text | ||
| MdpaEditor.save(self) | ||
|
|
@@ -38,7 +38,7 @@ def update_initial_effective_cell_pressure(self, initial_effective_cell_pressure | |
| replacer = self._replacer_factory(initial_effective_cell_pressure) | ||
| new_text, count = re.subn(pattern, replacer, self.raw_text) | ||
| if count == 0: | ||
| log_message("Could not update initial effective cell pressure.", "Warning") | ||
| log_message("Could not update initial effective cell pressure.", "warn") | ||
| else: | ||
| self.raw_text = new_text | ||
| MdpaEditor.save(self) | ||
|
|
@@ -50,7 +50,7 @@ def update_first_timestep(self, num_steps, end_time): | |
| replacer = self._replacer_factory(first_timestep) | ||
| new_text, count = re.subn(pattern, replacer, self.raw_text) | ||
| if count == 0: | ||
| log_message("Could not apply the first time step.", "Warning") | ||
| log_message("Could not apply the first time step.", "warn") | ||
| else: | ||
| self.raw_text = new_text | ||
| MdpaEditor.save(self) | ||
|
|
@@ -62,7 +62,19 @@ def update_end_time(self, end_time): | |
| new_text, count = re.subn(pattern, replacement, self.raw_text) | ||
|
|
||
| if count == 0: | ||
| log_message("Could not update the end time.", "Warning") | ||
| log_message("Could not update the end time.", "warn") | ||
| else: | ||
| self.raw_text = new_text | ||
| MdpaEditor.save(self) | ||
|
|
||
| def update_middle_maximum_strain(self, maximum_strain): | ||
| pattern = r'\$middle_maximum_strain\b' | ||
| prescribed_middle_displacement = (-maximum_strain / 2) / 100 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just for my understanding, is this the average between the max and 0? To me it's not clear why we need a minus sign and why we need to divide by 100.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah.. yeah probably not a very clear coding from my side :D
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The shear strain and shear stress ( like any other strain or stress ) are uniform in these tests. To get such a uniform strain the motion of the nodes is prescribed such that the bottom nodes do not move, the top nodes move all with the same distance and the nodes at half the height of the specimen move half the distance of the top nodes.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear, I missed the '%' that is clearly there in the GUI and the rest is clear from both your explanations |
||
|
|
||
| replacer = self._replacer_factory(prescribed_middle_displacement) | ||
| new_text, count = re.subn(pattern, replacer, self.raw_text) | ||
| if count == 0: | ||
| log_message("Could not update middle maximum strain.", "warn") | ||
| else: | ||
| self.raw_text = new_text | ||
| MdpaEditor.save(self) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| import numpy as np | ||
| from ui_logger import log_message | ||
| from ui_labels import ( | ||
| SIGMA1_LABEL, SIGMA3_LABEL, SIGMA1_SIGMA3_DIFF_LABEL, VERTICAL_STRAIN_LABEL, | ||
| VOLUMETRIC_STRAIN_LABEL, SHEAR_STRAIN_LABEL, SHEAR_STRESS_LABEL, EFFECTIVE_STRESS_LABEL, | ||
| MOBILIZED_SHEAR_STRESS_LABEL, P_STRESS_LABEL, Q_STRESS_LABEL, TITLE_SIGMA1_VS_SIGMA3, | ||
| TITLE_DIFF_PRINCIPAL_SIGMA_VS_STRAIN, TITLE_VOL_VS_VERT_STRAIN, TITLE_MOHR, TITLE_P_VS_Q, TITLE_SHEAR_VS_STRAIN, | ||
| LEGEND_MC, LEGEND_MC_FAILURE | ||
| ) | ||
|
|
||
|
|
||
| def plot_principal_stresses_triaxial(ax, sigma_1, sigma_3): | ||
WPK4FEM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ax.plot(sigma_3, sigma_1, '-', color='blue', label=TITLE_SIGMA1_VS_SIGMA3) | ||
| ax.set_title(TITLE_SIGMA1_VS_SIGMA3) | ||
| ax.set_xlabel(SIGMA3_LABEL) | ||
| ax.set_ylabel(SIGMA1_LABEL) | ||
| ax.grid(True) | ||
| ax.locator_params(nbins=8) | ||
|
|
||
| min_val = 0 | ||
| max_val_x = max(sigma_3) | ||
| max_val_y = min(sigma_1) | ||
| padding_x = 0.1 * (max_val_x - min_val) | ||
| padding_y = 0.1 * (max_val_y - min_val) | ||
| ax.set_xlim(min_val, max_val_x + padding_x) | ||
| ax.set_ylim(min_val, max_val_y + padding_y) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_delta_sigma_triaxial(ax, vertical_strain, sigma_diff): | ||
| ax.plot(vertical_strain, sigma_diff, '-', color='blue', label=SIGMA1_SIGMA3_DIFF_LABEL) | ||
| ax.set_title(TITLE_DIFF_PRINCIPAL_SIGMA_VS_STRAIN) | ||
| ax.set_xlabel(VERTICAL_STRAIN_LABEL) | ||
| ax.set_ylabel(SIGMA1_SIGMA3_DIFF_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
| ax.locator_params(nbins=8) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_volumetric_vertical_strain_triaxial(ax, vertical_strain, volumetric_strain): | ||
| ax.plot(vertical_strain, volumetric_strain, '-', color='blue', label=TITLE_VOL_VS_VERT_STRAIN) | ||
| ax.set_title(TITLE_VOL_VS_VERT_STRAIN) | ||
| ax.set_xlabel(VERTICAL_STRAIN_LABEL) | ||
| ax.set_ylabel(VOLUMETRIC_STRAIN_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
| ax.invert_yaxis() | ||
| ax.locator_params(nbins=8) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_mohr_coulomb_triaxial(ax, sigma_1, sigma_3, cohesion=None, friction_angle=None): | ||
| if np.isclose(sigma_1, sigma_3): | ||
| log_message("σ₁ is equal to σ₃. Mohr circle collapses to a point.", "warn") | ||
rfaasse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| center = (sigma_1 + sigma_3) / 2 | ||
| radius = (sigma_1 - sigma_3) / 2 | ||
| theta = np.linspace(0, np.pi, 200) | ||
| sigma = center + radius * np.cos(theta) | ||
| tau = -radius * np.sin(theta) | ||
|
|
||
| ax.plot(sigma, tau, label=LEGEND_MC, color='blue') | ||
|
|
||
| if cohesion is not None and friction_angle is not None: | ||
| phi_rad = np.radians(friction_angle) | ||
| x_line = np.linspace(0, sigma_1, 200) | ||
| y_line = x_line * np.tan(phi_rad) - cohesion | ||
| ax.plot(x_line, -y_line, 'r--', label=LEGEND_MC_FAILURE) | ||
| ax.legend(loc='upper left') | ||
|
|
||
| ax.set_title(LEGEND_MC) | ||
| ax.set_xlabel(EFFECTIVE_STRESS_LABEL) | ||
| ax.set_ylabel(MOBILIZED_SHEAR_STRESS_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
| ax.set_xlim(left=0, right= 1.2*np.max(sigma_1)) | ||
| ax.set_ylim(bottom=0, top = -0.6*np.max(sigma_1)) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_p_q_triaxial(ax, p_list, q_list): | ||
| ax.plot(p_list, q_list, '-', color='blue', label=TITLE_P_VS_Q) | ||
| ax.set_title(TITLE_P_VS_Q) | ||
| ax.set_xlabel(P_STRESS_LABEL) | ||
| ax.set_ylabel(Q_STRESS_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
| ax.locator_params(nbins=8) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_principal_stresses_direct_shear(ax, sigma_1, sigma_3): | ||
| ax.plot(sigma_3, sigma_1, '-', color='blue', label=TITLE_SIGMA1_VS_SIGMA3) | ||
| ax.set_title(TITLE_SIGMA1_VS_SIGMA3) | ||
| ax.set_xlabel(SIGMA3_LABEL) | ||
| ax.set_ylabel(SIGMA1_LABEL) | ||
| ax.grid(True) | ||
| ax.locator_params(nbins=8) | ||
|
|
||
| min_x, max_x = min(sigma_3), max(sigma_3) | ||
| min_y, max_y = min(sigma_1), max(sigma_1) | ||
| x_padding = 0.1 * (max_x - min_x) if max_x > min_x else 1.0 | ||
| y_padding = 0.1 * (max_y - min_y) if max_y > min_y else 1.0 | ||
| ax.set_xlim(min_x - x_padding, max_x + x_padding) | ||
| ax.set_ylim(min_y - y_padding, max_y + y_padding) | ||
|
|
||
| ax.invert_xaxis() | ||
| ax.invert_yaxis() | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_strain_stress_direct_shear(ax, shear_strain_xy, shear_stress_xy): | ||
| gamma_xy = 2 * np.array(shear_strain_xy) | ||
| ax.plot(np.abs(gamma_xy), np.abs(shear_stress_xy), '-', color='blue', label=TITLE_SHEAR_VS_STRAIN) | ||
| ax.set_title(TITLE_SHEAR_VS_STRAIN) | ||
| ax.set_xlabel(SHEAR_STRAIN_LABEL) | ||
| ax.set_ylabel(SHEAR_STRESS_LABEL) | ||
| ax.grid(True) | ||
| ax.locator_params(nbins=8) | ||
| ax.minorticks_on() | ||
|
|
||
| def plot_mohr_coulomb_direct_shear(ax, sigma_1, sigma_3, cohesion=None, friction_angle=None): | ||
| if np.isclose(sigma_1, sigma_3): | ||
| log_message("σ₁ is equal to σ₃. Mohr circle collapses to a point.", "warn") | ||
| center = (sigma_1 + sigma_3) / 2 | ||
| radius = (sigma_1 - sigma_3) / 2 | ||
| theta = np.linspace(0, np.pi, 400) | ||
| sigma = center + radius * np.cos(theta) | ||
| tau = -radius * np.sin(theta) | ||
|
|
||
| ax.plot(sigma, tau, label=LEGEND_MC, color='blue') | ||
|
|
||
| if cohesion is not None and friction_angle is not None: | ||
| phi_rad = np.radians(friction_angle) | ||
| max_sigma = center + radius | ||
| x_line = np.linspace(0, max_sigma * 1.5, 400) | ||
| y_line = x_line * np.tan(phi_rad) - cohesion | ||
| ax.plot(x_line, -y_line, 'r--', label=LEGEND_MC_FAILURE) | ||
| ax.legend(loc='upper left') | ||
|
|
||
| ax.set_title(LEGEND_MC) | ||
| ax.set_xlabel(EFFECTIVE_STRESS_LABEL) | ||
| ax.set_ylabel(MOBILIZED_SHEAR_STRESS_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
|
|
||
| epsilon = 0.1 | ||
| relative_diff = np.abs(sigma_1 - sigma_3) / max(np.abs(sigma_1), 1e-6) | ||
|
|
||
| if relative_diff < epsilon: | ||
| ax.set_xlim(center - (1.2 * radius), center + (1.2 * radius)) | ||
| ax.set_ylim(bottom=0, top = -0.9*(np.max(sigma_1) - np.max(sigma_3))) | ||
|
|
||
| else: | ||
| if sigma_1 > 0 or sigma_3 > 0: | ||
| ax.set_xlim(left=1.2*np.max(sigma_3), right=1.2*np.max(sigma_1)) | ||
| ax.set_ylim(bottom=0, top = -0.9*(np.max(sigma_1) - np.max(sigma_3))) | ||
| else: | ||
| ax.set_xlim(left=0, right=1.2*np.max(sigma_1)) | ||
| ax.set_ylim(bottom=0, top = -0.9*np.max(sigma_1)) | ||
|
|
||
|
|
||
| ax.minorticks_on() | ||
|
|
||
| def plot_p_q_direct_shear(ax, p_list, q_list): | ||
| ax.plot(p_list, q_list, '-', color='blue', label=TITLE_P_VS_Q) | ||
| ax.set_title(TITLE_P_VS_Q) | ||
| ax.set_xlabel(P_STRESS_LABEL) | ||
| ax.set_ylabel(Q_STRESS_LABEL) | ||
| ax.grid(True) | ||
| ax.invert_xaxis() | ||
| ax.set_xlim(left=0, right=1.2*np.max(p_list)) | ||
| ax.locator_params(nbins=8) | ||
| ax.minorticks_on() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder about the tau_xy indication in the picture. tau_xy is the shear stress that would appear on the contact of the 2 moving boxes in the picture. The test works with either a force or a prescribed displacement on the side which leads to a shear stress in the contact zone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to fix that in the next PR.