.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples\advanced\stress_postprocessing.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_advanced_stress_postprocessing.py: .. _ref_stress_postprocessing: Motor-CAD Stress post-processing example script =============================================== This example provides post-processing for Motor-CAD rotor stress results. The stress results are loaded, and estimates for non-linear stress and strain results are calculated from Motor-CAD's linear stress results using the Neuber and Glinka correction methods. .. GENERATED FROM PYTHON SOURCE LINES 35-37 Perform required imports ------------------------ .. GENERATED FROM PYTHON SOURCE LINES 37-48 .. code-block:: Python import math import pathlib import tempfile import uuid import matplotlib.pyplot as plt import numpy as np import ansys.motorcad.core as pymotorcad .. GENERATED FROM PYTHON SOURCE LINES 49-51 Utility functions to check non-linear material data --------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 51-116 .. code-block:: Python def check_youngs_modulus(non_linear_strain, non_linear_stress, youngs_modulus): """Check the initial slope of the non-linear stress strain curve matches the Young's modulus. Parameters ---------- non_linear_strain : list or ndarray Strain values non_linear_stress : list or ndarray Corresponding stress values in MPa youngs_modulus : float Young's modulus in MPa Returns ------- None Raises ------ ValueError If the initial slope is not consistent with the Young's modulus. """ initial_youngs_modulus = (non_linear_stress[1] - non_linear_stress[0]) / ( non_linear_strain[1] - non_linear_strain[0] ) # Error if notably different if not math.isclose(initial_youngs_modulus, youngs_modulus, rel_tol=0.01, abs_tol=0.1): raise ValueError( "Youngs Modulus and initial slope of non-linear data are different, " "please check the inputs. Initial slope is " + str(initial_youngs_modulus) + " MPa " + "Young's modulus is " + str(youngs_modulus) + " MPa" ) def find_divergence_point(non_linear_strain, non_linear_stress, youngs_modulus): """Find last point where the non-linear stress strain curve is on the linear region. Parameters ---------- non_linear_strain : list or ndarray Strain values non_linear_stress : list or ndarray Corresponding stress values in MPa youngs_modulus : float Young's modulus in MPa Returns ------- float The last stress point in the linear range """ for i in range(1, len(non_linear_stress)): if not math.isclose( non_linear_stress[i] / non_linear_strain[i], youngs_modulus, rel_tol=0.0001 ): return non_linear_stress[i - 1] # Return maximum stress in list if no divergence found return non_linear_stress[-1] .. GENERATED FROM PYTHON SOURCE LINES 117-119 Classes to store and manipulate stress and FEA data --------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 119-636 .. code-block:: Python class Element: """Data for a 1st order triangular element and its associated stress and strain Parameters ---------- tri_index : int The triangle element index number node_1 : int The ID of the first node in this element node_2 : int The ID of the second node in this element node_3 : int The ID of the third node in this element x : float The X position in mm of the element y : float The Y position in mm of the element s_x : float The X direction stress component in MPa s_y The Y direction stress component in MPa t_xy The XY plane shear stress in MPa sp_1 The first principal stress in MPa sp_2 The second principal stress in MPa svm The Von Mises stress in MPa u_x The X direction displacement in mm u_y The Y direction displacement in mm Attributes ---------- stress_nonlinear_neuber : float The corrected equivalent stress using the Neuber correction in MPa. Populated by apply_neuber_correction strain_nonlinear_neuber : float The corrected equivalent total strain using the Neuber correction. Populated by apply_neuber_correction strain_plastic_neuber : float The plastic strain using the Neuber correction. Populated by apply_neuber_correction stress_nonlinear_glinka : float The corrected equivalent stress using the Glinka correction in MPa. Populated by apply_glinka_correction strain_nonlinear_glinka : float he corrected equivalent total strain using the Glinka correction. Populated by apply_glinka_correction strain_plastic_glinka : float The plastic strain using the Glinka correction. Populated by apply_glinka_correction """ def __init__( self, tri_index, node_1, node_2, node_3, x, y, s_x, s_y, t_xy, sp_1, sp_2, svm, u_x, u_y ): self.tri_index = tri_index self.node_1 = node_1 self.node_2 = node_2 self.node_3 = node_3 self.x = x self.y = y self.s_x = s_x self.s_y = s_y self.t_xy = t_xy self.sp_1 = sp_1 self.sp_2 = sp_2 self.svm = svm self.u_x = u_x self.u_y = u_y self.stress_nonlinear_neuber = 0 self.strain_nonlinear_neuber = 0 self.strain_plastic_neuber = 0 self.stress_nonlinear_glinka = 0 self.strain_nonlinear_glinka = 0 self.strain_plastic_glinka = 0 def apply_neuber_correction(self, youngs_modulus, non_linear_strain, non_linear_stress): """Update the Neuber correction estimates from the Von Mises stress. Parameters ---------- youngs_modulus : float The Young's modulus used in the linear stress calculation. non_linear_strain, non_linear_stress : np.ndarray Corresponding arrays of strain (ratio) and stress (MPa) for the non-linear correction. """ elastic_stress = self.svm elastic_strain = elastic_stress / youngs_modulus elastic_stress_strain_product = elastic_stress * elastic_strain # Check input data is sensible check_youngs_modulus(non_linear_strain, non_linear_stress, youngs_modulus) # If on the elastic portion, just return inputs, so we don't get interpolation errors if elastic_stress < find_divergence_point( non_linear_strain, non_linear_stress, youngs_modulus ): self.strain_nonlinear_neuber = elastic_strain self.stress_nonlinear_neuber = elastic_stress self.strain_plastic_neuber = 0 return # Find a matching stress-strain product in the non-linear response # (This is the Neuber correction) non_linear_stress_strain_product = non_linear_stress * non_linear_strain # Error if out of range: if elastic_stress_strain_product > np.max(non_linear_stress_strain_product): raise ValueError( "Input too large (elastic stress strain product > maximum stress strain product in " "non-linear data). " "Elastic stress is " + str(elastic_stress) + ", elastic stress strain product is " + str(elastic_stress_strain_product) + ", maximum plastic stress strain product is " + str(np.max(non_linear_stress_strain_product)) ) # Lookup to find non-linear strain at matching stress strain product: equivalent_non_linear_strain = np.interp( elastic_stress_strain_product, non_linear_stress_strain_product, non_linear_strain ) # Lookup to find non-linear stress at this strain: equivalent_non_linear_stress = np.interp( equivalent_non_linear_strain, non_linear_strain, non_linear_stress ) # Find plastic strain plastic_strain = equivalent_non_linear_strain - elastic_strain self.strain_nonlinear_neuber = equivalent_non_linear_strain self.stress_nonlinear_neuber = equivalent_non_linear_stress self.strain_plastic_neuber = plastic_strain def apply_glinka_correction(self, youngs_modulus, non_linear_strain, non_linear_stress): """Update the Glinka correction estimates from the Von Mises stress. Parameters ---------- youngs_modulus : float The Young's modulus used in the linear stress calculation. non_linear_strain, non_linear_stress : np.ndarray Corresponding arrays of strain (ratio) and stress (MPa) for the non-linear correction. """ elastic_stress = self.svm elastic_strain = elastic_stress / youngs_modulus elastic_stress_strain_integral = 0.5 * elastic_strain * elastic_stress # Check input data is sensible check_youngs_modulus(non_linear_strain, non_linear_stress, youngs_modulus) # If on the elastic portion, just return inputs, so we don't get interpolation errors if elastic_stress < find_divergence_point( non_linear_strain, non_linear_stress, youngs_modulus ): self.strain_nonlinear_glinka = elastic_strain self.stress_nonlinear_glinka = elastic_stress self.strain_plastic_glinka = 0 return # Find a matching stress-strain integral in the non-linear response # (This is the Glinka correction) non_linear_stress_strain_integral = np.zeros(len(non_linear_stress)) for i in range(1, len(non_linear_stress)): # This assumes that our stress strain curve starts at zero, # and uses simple trapezium integration non_linear_stress_strain_integral[i] = ( non_linear_stress_strain_integral[i - 1] + (non_linear_strain[i] - non_linear_strain[i - 1]) * (non_linear_stress[i] + non_linear_stress[i - 1]) / 2 ) # Error if out of range: if elastic_stress_strain_integral > np.max(non_linear_stress_strain_integral): raise ValueError( "Input too large (elastic stress strain integral > " "maximum stress strain integral in non-linear data). " "Elastic stress is " + str(elastic_stress) + ", elastic stress strain integral is " + str(elastic_stress_strain_integral) + ", maximum plastic stress strain integral is " + str(np.max(non_linear_stress_strain_integral)) ) # Lookup to find non-linear strain at matching stress strain integral: equivalent_non_linear_strain = np.interp( elastic_stress_strain_integral, non_linear_stress_strain_integral, non_linear_strain ) # Lookup to find non-linear stress at this strain: equivalent_non_linear_stress = np.interp( equivalent_non_linear_strain, non_linear_strain, non_linear_stress ) # Find plastic strain plastic_strain = equivalent_non_linear_strain - elastic_strain self.strain_nonlinear_glinka = equivalent_non_linear_strain self.stress_nonlinear_glinka = equivalent_non_linear_stress self.strain_plastic_glinka = plastic_strain class StressRegion: """Data for a stressed region, including element stress data and region properties. Attributes ---------- region_name : str The name of the region reg_code : int The region identifier code from the FEA youngs_modulus : float The region's Young's modulus poissons_ratio : float The region's Poisson's ratio elements : list of Element List of elements that make up the region """ def __init__(self): self.region_name = "" self.reg_code = 0 self.youngs_modulus = 0 self.poissons_ratio = 0 self.elements = [] def add_element( self, tri_index, node_1, node_2, node_3, x, y, s_x, s_y, t_xy, sp_1, sp_2, svm, u_x, u_y ): """Add an element to the region with results from a linear elastic calculation. Parameters ---------- tri_index : int The triangle element index number node_1 : int The ID of the first node in this element node_2 : int The ID of the second node in this element node_3 : int The ID of the third node in this element x : float The X position in mm of the element y : float The Y position in mm of the element s_x : float The X direction stress component in MPa s_y The Y direction stress component in MPa t_xy The XY plane shear stress in MPa sp_1 The first principal stress in MPa sp_2 The second principal stress in MPa svm The Von Mises stress in MPa u_x The X direction displacement in mm u_y The Y direction displacement in mm """ self.elements.append( Element( tri_index, node_1, node_2, node_3, x, y, s_x, s_y, t_xy, sp_1, sp_2, svm, u_x, u_y ) ) def get_number_elements(self): """Return the number of elements in the region. Returns ------- int Number of elements in the region. """ return len(self.elements) def get_sp1(self): """Return the first principal stress as a list in MPa.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].sp_1) return result_array def get_sp2(self): """Return the second principal stress as a list in MPa.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].sp_2) return result_array def get_svm(self): """Return the Von Mises stress as a list in MPa.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].svm) return result_array def get_stress_nonlinear_neuber(self): """Return the estimated stress with the Neuber correction as a list in MPa.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].stress_nonlinear_neuber) return result_array def get_strain_nonlinear_neuber(self): """Return the estimated total strain with the Neuber correction as a list.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].strain_nonlinear_neuber) return result_array def get_strain_plastic_neuber(self): """Return the estimated plastic strain with the Neuber correction as a list.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].strain_plastic_neuber) return result_array def get_stress_nonlinear_glinka(self): """Return the estimated stress with the Glinka correction as a list in MPa.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].stress_nonlinear_glinka) return result_array def get_strain_nonlinear_glinka(self): """Return the estimated total strain with the Glinka correction as a list.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].strain_nonlinear_glinka) return result_array def get_strain_plastic_glinka(self): """Return the estimated plastic strain with the Glinka correction as a list.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].strain_plastic_glinka) return result_array def get_x(self): """Return the X coordinate as a list in mm.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].x) return result_array def get_y(self): """Return the Y coordinate as a list in mm.""" result_array = [] for i in range(len(self.elements)): result_array.append(self.elements[i].y) return result_array def apply_corrections(self, non_linear_strain, non_linear_stress): """Update the Neuber and Glinka estimates using the Von Mises stress for all elements. Parameters ---------- non_linear_strain, non_linear_stress : np.ndarray Corresponding arrays of strain (ratio) and stress (MPa) for the non-linear correction. """ for i in range(len(self.elements)): self.elements[i].apply_neuber_correction( self.youngs_modulus, non_linear_strain, non_linear_stress ) self.elements[i].apply_glinka_correction( self.youngs_modulus, non_linear_strain, non_linear_stress ) # In principle, we could not apply a scaling based on the corrected stresses to the # s_x, s_y and t_xy stresses, so we have an offset to apply to account for relaxation # following plastic strain for later load cases. class StressRegions: """Data on stresses for multiple regions.""" def __init__(self): self._regions = [] def __getitem__(self, region_number): return self._regions[region_number] def __setitem__(self, region_number, data): self._regions[region_number] = data def __len__(self): return len(self._regions) def add_region(self): """Add a new region""" self._regions.append(StressRegion()) def get_stress_data(mc, clean_up=True): """Load stress data from Motor-CAD This function should be called after the stress calculation has been carried out using `do_mechanical_calculation`. Parameters ---------- mc : pymotorcad.motorcad_methods.MotorCAD The PyMotorCAD instance to use. clean_up : bool, default True If the temporary text file should be deleted after use. Returns ------- StressRegions The stress information for all regions. """ # Make a temporary filename temp_filename = pathlib.Path(tempfile.gettempdir()) / pathlib.Path(str(uuid.uuid4()) + ".txt") # The Motor-CAD FEA file always saves with '.' as a decimal separator, independent of regional # settings. Empty string for regions means we get all available regions mc.save_fea_data(str(temp_filename), 0, 0, "RegCode,X,Y,Sx,Sy,Txy,Sp1,Sp2,SVM,Ux,Uy", "", ",") # Open the file in_file = open(temp_filename, "r") # Read first line, second value will be length of element table (e.g. '1 41230 ElementsTable') split_line = in_file.readline().split(sep=" ") number_of_elements = int(split_line[1]) # Skip over 4 redundant lines (blank line, plus descriptive header) for i in range(4): in_file.readline() # Start with an empty set of regions stress_regions = StressRegions() # Read the element data for i in range(number_of_elements): split_line = in_file.readline().split(sep=",") # The region code is the 5th element, after the TriIndex, Node1, Node2 & Node3 reg_code = int(split_line[4]) # Increase the number of regions as required while reg_code > len(stress_regions): stress_regions.add_region() stress_regions[reg_code - 1].add_element( tri_index=int(split_line[0]), node_1=int(split_line[1]), node_2=int(split_line[2]), node_3=int(split_line[3]), # Note that split_line[4] is the region code, not stored per-element x=float(split_line[5]), y=float(split_line[6]), s_x=float(split_line[7]), s_y=float(split_line[8]), t_xy=float(split_line[9]), sp_1=float(split_line[10]), sp_2=float(split_line[11]), svm=float(split_line[12]), u_x=float(split_line[13]), u_y=float(split_line[14]), ) split_line = in_file.readline().split(sep=" ") # This should be the 2 XXX NodesTable line number_of_nodes = int(split_line[1]) # Skip over 4 redundant lines (blank line, plus descriptive header) for i in range(4): in_file.readline() # Read the nodal data for i in range(number_of_nodes): split_line = in_file.readline().split(sep=",") # TODO: We could store this data, to get nodal average stresses later. split_line = in_file.readline().split(sep=" ") # This should be the 3 XXX RegionsTable line number_of_regions = int(split_line[1]) # Skip over 4 redundant lines (blank line, plus descriptive header) for i in range(4): in_file.readline() if number_of_regions > len(stress_regions): raise ValueError("RegionsTable and element region codes do not match") # Read the region data for i in range(number_of_regions): split_line = in_file.readline().split(sep=",") this_region = int(split_line[0]) if this_region > len(stress_regions): raise ValueError("RegionsTable and element region codes do not match") stress_regions[this_region - 1].reg_code = this_region stress_regions[this_region - 1].youngs_modulus = float(split_line[1]) stress_regions[this_region - 1].poissons_ratio = float(split_line[2]) stress_regions[this_region - 1].region_name = split_line[-1].strip() # Tidy up in_file.close() # Delete the temp file if clean_up: temp_filename.unlink() else: print("Temporary file not deleted: " + str(temp_filename)) return stress_regions .. GENERATED FROM PYTHON SOURCE LINES 637-644 Main script, using the classes and methods defined above -------------------------------------------------------- Start Motor-CAD ~~~~~~~~~~~~~~~ Load a template (for users this would normally be replaced by `load_from_file()`, and disable popup messages. .. GENERATED FROM PYTHON SOURCE LINES 644-648 .. code-block:: Python mc = pymotorcad.MotorCAD() mc.set_variable("MessageDisplayState", 2) mc.load_template("e9") .. GENERATED FROM PYTHON SOURCE LINES 649-652 Run the stress calculation ~~~~~~~~~~~~~~~~~~~~~~~~~~ Set the shaft speed and run the mechanical stress calculation .. GENERATED FROM PYTHON SOURCE LINES 652-655 .. code-block:: Python mc.set_variable("ShaftSpeed", 15000) mc.do_mechanical_calculation() .. GENERATED FROM PYTHON SOURCE LINES 656-658 Read the stress data ~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 658-660 .. code-block:: Python stress_regions = get_stress_data(mc) .. GENERATED FROM PYTHON SOURCE LINES 661-663 Choose which regions to show data for ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 663-665 .. code-block:: Python region_names_to_postprocess = ["Rotor"] .. GENERATED FROM PYTHON SOURCE LINES 666-668 Plot the elastic stress data for each region ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. GENERATED FROM PYTHON SOURCE LINES 668-691 .. code-block:: Python for region_name_to_postprocess in region_names_to_postprocess: # Find matching regions for i in range(len(stress_regions)): if stress_regions[i].region_name == region_name_to_postprocess: if stress_regions[i].get_number_elements() > 0: fig, ax = plt.subplots(1, 2, layout="constrained", sharey=True) ax[0].scatter( stress_regions[i].get_sp1(), stress_regions[i].get_sp2(), marker="." ) # , c=svm) ax[0].set_xlabel("Principal stress 1 [MPa]") ax[0].set_ylabel("Principal stress 2 [MPa]") ax[1].scatter( stress_regions[i].get_svm(), stress_regions[i].get_sp1(), marker="." ) # , c=svm) ax[1].scatter( stress_regions[i].get_svm(), stress_regions[i].get_sp2(), marker="x" ) # , c=svm) ax[1].legend(["Sp1", "Sp2"]) ax[1].set_xlabel("Von Mises Stress [MPa]") ax[1].set_ylabel("Principal Stress [MPa]") plt.suptitle(stress_regions[i].region_name) plt.show() .. image-sg:: /examples/advanced/images/sphx_glr_stress_postprocessing_001.png :alt: Rotor :srcset: /examples/advanced/images/sphx_glr_stress_postprocessing_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 692-696 Non-linear stress strain data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Our non-linear stress-strain data, in this case for a region with Young's modulus of 185 GPa, and with plastic deformation above 480 MPa. .. GENERATED FROM PYTHON SOURCE LINES 696-765 .. code-block:: Python non_linear_strain = np.array( [ 0, 0.0002, 0.0004, 0.0006, 0.0008, 0.001, 0.0012, 0.0014, 0.0016, 0.0018, 0.002, 0.0022, 0.0024, 0.0026, 0.0028, 0.003, 0.0032, 0.0034, 0.0036, 0.0038, 0.004, 0.0042, 0.0044, 0.0046, 0.0048, 0.005, 0.0052, 0.0054, 0.0056, 0.0058, ] ) non_linear_stress = np.array( [ 0, 37, 74, 111, 148, 185, 222, 259, 296, 333, 370, 407, 444, 481, 500, 520, 540, 560, 570, 580, 590, 600, 605, 610, 615, 620, 625, 630, 635, 640, ] ) .. GENERATED FROM PYTHON SOURCE LINES 766-770 Apply corrections ~~~~~~~~~~~~~~~~~ Apply the Glinka and Neuber stress corrections to the regions of interest using the region's `apply_corrections` method, and plot the results. .. GENERATED FROM PYTHON SOURCE LINES 770-890 .. code-block:: Python for region_name_to_postprocess in region_names_to_postprocess: # Find matching regions for i in range(len(stress_regions)): if stress_regions[i].region_name == region_name_to_postprocess: # Apply the actual stress correction here stress_regions[i].apply_corrections(non_linear_strain, non_linear_stress) # Print the maximum stresses and strains print(f"For region {stress_regions[i].region_name}:") print(f"Maximum elastic stress " f"{np.max(stress_regions[i].get_svm()):.6} MPa") print( f"Maximum stress with Neuber correction: " f"{np.max(stress_regions[i].get_stress_nonlinear_neuber()):.6} MPa" ) print( f"Maximum stress with Glinka correction: " f"{np.max(stress_regions[i].get_stress_nonlinear_glinka()):.6} MPa" ) print( f"Maximum plastic strain with Neuber correction: " f"{np.max(stress_regions[i].get_strain_plastic_neuber()):.6}" ) print( f"Maximum plastic strain with Glinka correction: " f"{np.max(stress_regions[i].get_strain_plastic_glinka()):.6}" ) # Plot: fig, ax = plt.subplots(3, 1, layout="constrained") # Stress vs strain ax[0].scatter( stress_regions[i].get_strain_nonlinear_neuber(), stress_regions[i].get_stress_nonlinear_neuber(), marker=".", ) ax[0].scatter( stress_regions[i].get_strain_nonlinear_glinka(), stress_regions[i].get_stress_nonlinear_glinka(), marker="x", ) ax[0].legend(["Neuber", "Glinka"]) ax[0].set_xlabel("Strain [-]") ax[0].set_ylabel("Stress [MPa]") # Plastic stress vs elastic stress ax[1].scatter( stress_regions[i].get_svm(), stress_regions[i].get_stress_nonlinear_neuber(), marker=".", ) ax[1].scatter( stress_regions[i].get_svm(), stress_regions[i].get_stress_nonlinear_glinka(), marker="x", ) ax[1].legend(["Neuber", "Glinka"]) ax[1].set_xlabel("Stress Von Mises [MPa]") ax[1].set_ylabel("Stress Adjusted [MPa]") # Plastic strain vs elastic stress ax[2].scatter( stress_regions[i].get_svm(), stress_regions[i].get_strain_plastic_neuber(), marker=".", ) ax[2].scatter( stress_regions[i].get_svm(), stress_regions[i].get_strain_plastic_glinka(), marker="x", ) ax[2].legend(["Neuber", "Glinka"]) ax[2].set_xlabel("Stress Von Mises [MPa]") ax[2].set_ylabel("Plastic strain [-]") plt.suptitle(stress_regions[i].region_name) plt.show() # Plot stress including correction, and plastic strain # Plot against element data X and Y (check exactly what this corresponds to, # assume element centre, but seems to be one node of triangle) cm = plt.colormaps["jet"] fig, ax = plt.subplots(2, 2, layout="constrained") plot1 = ax[0, 0].scatter( stress_regions[i].get_x(), stress_regions[i].get_y(), c=stress_regions[i].get_stress_nonlinear_neuber(), marker=".", cmap=cm, ) plt.colorbar(plot1, ax=ax[0, 0]) ax[0, 0].set_title("Stress (Neuber correction)") plot2 = ax[0, 1].scatter( stress_regions[i].get_x(), stress_regions[i].get_y(), c=stress_regions[i].get_stress_nonlinear_glinka(), marker=".", cmap=cm, ) plt.colorbar(plot2, ax=ax[0, 1]) ax[0, 1].set_title("Stress (Glinka correction)") plot3 = ax[1, 0].scatter( stress_regions[i].get_x(), stress_regions[i].get_y(), c=stress_regions[i].get_strain_plastic_neuber(), marker=".", cmap=cm, ) plt.colorbar(plot3, ax=ax[1, 0]) ax[1, 0].set_title("Plastic strain (Neuber correction)") plot4 = ax[1, 1].scatter( stress_regions[i].get_x(), stress_regions[i].get_y(), c=stress_regions[i].get_strain_plastic_glinka(), marker=".", cmap=cm, ) plt.colorbar(plot4, ax=ax[1, 1]) ax[1, 1].set_title("Plastic strain (Glinka correction)") plt.show() .. rst-class:: sphx-glr-horizontal * .. image-sg:: /examples/advanced/images/sphx_glr_stress_postprocessing_002.png :alt: Rotor :srcset: /examples/advanced/images/sphx_glr_stress_postprocessing_002.png :class: sphx-glr-multi-img * .. image-sg:: /examples/advanced/images/sphx_glr_stress_postprocessing_003.png :alt: Stress (Neuber correction), Stress (Glinka correction), Plastic strain (Neuber correction), Plastic strain (Glinka correction) :srcset: /examples/advanced/images/sphx_glr_stress_postprocessing_003.png :class: sphx-glr-multi-img .. rst-class:: sphx-glr-script-out .. code-block:: none For region Rotor: Maximum elastic stress 535.995 MPa Maximum stress with Neuber correction: 519.115 MPa Maximum stress with Glinka correction: 510.404 MPa Maximum plastic strain with Neuber correction: 9.38821e-05 Maximum plastic strain with Glinka correction: 6.77118e-06 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 21.547 seconds) .. _sphx_glr_download_examples_advanced_stress_postprocessing.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: stress_postprocessing.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: stress_postprocessing.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: stress_postprocessing.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_