Create a field and plot results
Hey,
I want to investigate the fatigue of given loads steps with DPF in Python. Therefore, I extract all data from the *.rst file and compute my damage value for each node (e.g., for a named selection). Finally, this results in a list of node ids (resulting from the named selection) and associated damage values (from my computation).
Can you please help me to create a "new" field (e.g., damage)? How can I plot this results/field in a 3D contour plot?
Thank you,
Thomas
Best Answers
-
Glad you like those posts! And nice to see that you've made great progress! You can plot the result on custom space domains, see this page for some examples: https://dpf.docs.pyansys.com/examples/00-basic/09-results_over_space_subset.html#sphx-glr-examples-00-basic-09-results-over-space-subset-py
0 -
Below you will find a summary of the source code.
# -*- coding: utf-8 -*- """ Created on Wed Dec 28 12:37:46 2022 @author: t.lauss """ from ansys.dpf import core as dpf from ansys.dpf.core import operators as ops import functions # contains all functions for fatigue computation import os # load result files file_name = r"file.rst" link_file = r"...path_to_file..." your_result_file = os.path.join(link_file,file_name) # load model and print model infos model = dpf.Model(your_result_file) # Print available named selections print('Named selections in model:', model.metadata.available_named_selections) # Restrict data to a specific named selection ns_operator = ops.scoping.on_named_selection() ns_operator.inputs.data_sources.connect(model) ns_operator.inputs.named_selection_name.connect('ROD_CYL_FACE') # Get node numbers for nodes in named selection mesh_data = ns_operator.outputs.mesh_scoping.get_data() node_ids = mesh_data.ids # Extract principal streses on the named selection principal_stress = ops.result.stress_principal_1(data_sources=model) # Create list for result sets (every time id is associated to a load step for fatigue analysis) time_ids = list(range(1, model.metadata.time_freq_support.n_sets+1)) # Restrict scoping to named selection principal_stress.inputs.mesh_scoping.connect(ns_operator.outputs.mesh_scoping) principal_stress.inputs.time_scoping.connect(time_ids) # extract fields for named selection and load steps fields = principal_stress.outputs.fields_container.get_data() # number of nodes N_nodes = len(mesh_data.ids) # number of time steps N_time = len(time_ids) # Parameter for fatigue calculation ... # Damage computation for all nodes of named selection damage = N_nodes*[0.0] for i in range(0,N_nodes):# loop over all nodes node_id = node_ids[i] # node id s1 = N_time*[0.0] # temporary list of maximum principla stress for one node and all time steps idRed = N_time*[0] # load step ID for stress calculation for j in range(0,N_time): # loop obrt all time steps # extract maximum principal stress for time step and node s1[j] = fields[j].get_entity_data_by_id(node_ids[i])[0] # get reduced pivoted load step IDs idRed[j] = N_time-j # Initialize damage value with zero Di = 0.0 # associate stress data with fatigue spectrum (with reduced ID and load IDs) # get list of stresses to be classified by rainflow counting data = functions.nodeHashListLeewardLC1(idRed,s1) # rainflow clasification res = functions.rainflowCount(data) N_Count = len(res) # Damage calculation for each rainflow cycle for k in range(0,N_Count): smax = res[k][0][0] smin = res[k][0][1] count = res[k][1] Di = Di + functions.getDamage(...) # ...Do this for all load cases... # Store accumulated damage value in list damage[i] = Di # Print infos to console print(node_id, Di, i/N_nodes*100, "%") # get the location and the max. Damage value maxDamage = max(damage) maxIndex = damage.index(maxDamage) print("max. Damage: ", max(damage), "at Node: ", node_ids[maxIndex]) ################################################################ ############# Plot the damage in a 3d contour plot ############# ################################################################ # create a field which contains the damage value at particular nodes field_damage = dpf.fields_factory.create_scalar_field(N_nodes, dpf.locations.nodal) # store data in field at nodes for i in range(0,N_nodes): field_damage.append(damage[i], node_ids[i]) # extract mesh for body with named selection name "RODEND" mesh_scoping = model.metadata.named_selection("RODEND") mesh = model.metadata.meshed_region op = dpf.operators.mesh.from_scoping(scoping=mesh_scoping, inclusive=1, mesh=mesh) result_mesh = op.outputs.mesh() # assign mesh to field that contains the damage values field_damage.meshed_region = result_mesh # plot the damage values sargs = dict(title="damage", fmt="%.2e") field_damage.plot(scalar_bar_args=sargs, meshed_region=result_mesh, screenshot='image.png', cpos=[(0.0, -80.0, 20.0), (-0.1, -0.1, -1.0), (0.0, 0.8, -0.1)]) # You can set the camera positions using the ``cpos`` argument. # The three tuples in the list for the ``cpos`` argument represent the camera # position, focal point, and view respectively.
1
Answers
-
Hi @t.lauss , to create a new field, use
dpf.fields_factory
. An example is available here: https://dpf.docs.pyansys.com/examples/00-basic/03-create_entities.htmlPlotting options are explained there: https://dpf.docs.pyansys.com/examples/05-plotting/00-basic_plotting.html#sphx-glr-examples-05-plotting-00-basic-plotting-py
If you're looking into plotting the results in Workbench Mechanical, you will have to use a Python Result. This post could be helpful: https://www.linkedin.com/pulse/script-tip-friday-how-sum-damage-results-structural-analysis/
1 -
Thank you for your help. The examples and the skript tips on friday are excellent, i absolutely like this.
I created a scalar field with the dpf.fields_factory and store all damage values and the corresponding node ids in the field. I think this is working now.
The problem now is that the results at the named selcetion (see Fig. 1) is hidden by other bodies (see Fig. 2). Is it possible to plot only the mesh and fileds of the named selection and/or is it possible to hide bodies during plotting?
0 -
I had already tried to create the plot using this example, but unfortunately I did not succeed.
Here is my code (damage is a list with the damage values and node_ids is a list of same size with the associated node numbers)
# create a field which contains the damage value at particular nodes # this is a “reserve” mechanism, not a resize one. This means that you need to append data to grow the size of your field. field_damage = dpf.fields_factory.create_scalar_field(N_nodes, dpf.locations.nodal) # store data in field at nodes for i in range(0,N_nodes): field_damage.append(Damage[i], node_ids[i]) # create a mesh scoping for the named selection "ROD_CYL_FACE" mesh_scoping = model.metadata.named_selection("ROD_CYL_FACE") print(mesh_scoping) #???????????????? NOT WORKING ???????????????? field_damage.meshed_region = ops.mesh.from_scoping(mesh_scoping) # plot sargs = dict(title="damage", fmt="%.2e") field_damage.plot(scalar_bar_args=sargs)
Output of print(mesh_scoping): DPF Scoping: with Nodal location and 2175 entities
After the mesh_scoping I don't really know how to proceed. How can I associate the mesh_scoping and the field_damage?
Moreover, in the mentioned DPF examples I do not found how to plot only the results of one body and the other bodys are not visible. My problem is that the interesting damage region is hidden by other bodys and therefore not visible for me.
0 -
Thank you for your help! My code works now 😀
1 -
Thanks @t.lauss , happy to help! If you are willing to share, feel free to post your code as an example here for others to benefit from.
0 -
Thanks a lot for sharing @t.lauss ! I'm sure this will be of great help to other users!
1