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