Get successive elements with max user-defined result value.

I have a user-defined result (UDR)created in Mechanical. I'd like to select an element, and based on that starting point get the successive N elements with UDR value in the depth of the solid body.
Answers
-
This post combines and adapts the code written in these two posts:
- Get successive elements with max stress in depth of structure: https://discuss.ansys.com/discussion/2082/get-successive-elements-with-max-stress-in-depth-of-structure/p1?new=1
- Convert PlotData of User Defined Result to a DPF field and plot it: https://discuss.ansys.com/discussion/2080/convert-plotdata-of-user-defined-result-to-a-dpf-field-and-plot-it/p1?new=1
A user-defined result (in this example, a nodal result, ie with Averaged option) is inserted in Mechanical:
The properties of the Python Result allows the user to select the UDR, the element starting point (thanks to a named selection), and the number of layers to be considered:
This is achieved by editing the Property Provider as follows:
def reload_props(): this.PropertyProvider = None # Create the property instance provider = Provider() input_group = provider.AddGroup("Input") ns_prop = input_group.AddProperty("Elemental Named Selection Name", Control.Expression) udr_prop = input_group.AddProperty("UDR Name", Control.Expression) nb_layer_prop = input_group.AddProperty("Number of Layers", Control.Double) output_group = provider.AddGroup("Output") output_prop = output_group.AddProperty("Average stress over selected elements", Control.Double) output_prop.CanParameterize = True output_prop.ParameterType = ParameterType.Output # Connects the provider instance back to the object by setting the PropertyProvider member on this, 'this' being the # current instance of the Python Code object. this.PropertyProvider = provider
The code for the Python Result is the combination of the codes shared in the two posts mentioned above, with some specifics:
- The values in the user-defined result are transformed into a DPF field, and this field is passed to a fields container
- The fields container is passed to an averaging operator to transform nodal data into elemental data. IMPORTANT NOTE: this part explains why plotted results might differ from the ones obtained in Mechanical, as the averaging method and the order of averaging is not the same.
The code for the Python Result is:
def post_started(sender, analysis):# Do not edit this line define_dpf_workflow(analysis) def define_dpf_workflow(analysis): # import DPF import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) # Connect to result file dataSource = dpf.DataSources(analysis.ResultFileName) # Retrieve property values selection_name = str(this.GetCustomPropertyByPath("Input/Elemental Named Selection Name").Value) udr_name = str(this.GetCustomPropertyByPath("Input/UDR Name").Value) n_layers = int(this.GetCustomPropertyByPath("Input/Number of Layers").Value) # Retrieve mesh model=dpf.Model(dataSource) mesh=model.Mesh # whole mesh skin_mesh=dpf.operators.mesh.skin(mesh) # skin mesh skin_nodes=skin_mesh.outputs.getnodes_mesh_scoping() # get nodes of skin mesh conv_to_elems=dpf.operators.scoping.transpose(mesh_scoping=skin_nodes,meshed_region=mesh) # convert to elements skin_elems_scoping=conv_to_elems.outputs.getmesh_scoping_as_scoping() # create a scoping with skin elements # Access User Defined Result and create a field out of it udr = ExtAPI.DataModel.GetObjectsByName(udr_name)[0] nb_nodes = len(udr.PlotData['Node']) # get number of nodes udr_field = dpf.FieldsFactory.CreateScalarField(nb_nodes) # instanciate field udr_field.MeshedRegionSupport = mesh # attach mesh udr_field.ScopingIds = udr.PlotData['Node'] # give list of nodes udr_field.Data = [0. for i in range(0,nb_nodes)]# fill field with zeros node_ids = udr.PlotData['Node'] values = [value for value in udr.PlotData['Values']] for ii in range(0,nb_nodes): index=udr_field.ScopingIds.IndexOf(node_ids[ii]) # get index of node in created field udr_field.UpdateEntityDataByEntityIndex(index,[values[ii]]) # Create fields container from field field_container = dpf.FieldsContainer() field_container.Labels = ['time'] field_container.Add(udr_field,{'time':1}) # Transform nodal field to elemental field s = dpf.operators.averaging.nodal_to_elemental_fc() s.inputs.fields_container.Connect(field_container) s.inputs.mesh.Connect(mesh) # Get starting element from named selection selection_name=selection_name.upper() # Start element elem=dpf.operators.scoping.on_named_selection(named_selection_name=selection_name, requested_location='Elemental',data_sources=dataSource) elem_scoping=elem.outputs.getmesh_scoping() # Retrieve max stress on selected element s.inputs.scoping.Connect(elem_scoping) s_max=dpf.operators.min_max.min_max(s.outputs.getfields_container()[0]) # Collect element id and stress values elem_ids=[elem.outputs.getmesh_scoping().Ids[0]] smax=[s_max.outputs.field_max.GetData().Data[0]] # Find next n elements with highest stresses but don't take into account # any element with free surface (i.e. linked to outer skin) for i in range(0,n_layers): conv_to_nodes=dpf.operators.scoping.transpose(mesh_scoping=elem_scoping,meshed_region=mesh) # get nodes of selected element neighbour_mesh_op= dpf.operators.mesh.from_scoping(scoping=conv_to_nodes,mesh=mesh) # get elements attached to nodes # Remove skin related elements diff_scoping=dpf.operators.scoping.intersect(scopingA=neighbour_mesh_op.outputs.getmesh().ElementScoping,scopingB=skin_elems_scoping) inside_elements_scoping=diff_scoping.outputs.scopingA_min_intersection.GetData() # Remove any of the previously identified elements from the scoping el_ids=list(inside_elements_scoping.Ids) for el in elem_ids: try: el_ids.remove(el) except: pass inside_elements_scoping.Ids=el_ids # Find element with highest stress value s.inputs.scoping.Connect(inside_elements_scoping) s_max=dpf.operators.min_max.min_max(s.outputs.getfields_container()[0]) # Collect element id and stress values next_elem_id=s_max.outputs.field_max.GetData().ScopingIds[0] elem_ids.append(next_elem_id) smax.append(s_max.outputs.field_max.GetData().Data[0]) # Before ending the loop, update start element to be last one found elem_scoping.Ids=[next_elem_id] # Set output value this.GetCustomPropertyByPath("Output/Average stress over selected elements").Value=sum(smax)/len(smax) # Display mesh will be only selected elements selected_scoping=dpf.Scoping() selected_scoping.Ids=elem_ids selected_scoping.Location='Elemental' s.inputs.scoping.Connect(selected_scoping) display_mesh=dpf.operators.mesh.from_scoping(scoping=selected_scoping,mesh=mesh) dpf_workflow = dpf.Workflow() dpf_workflow.Add(s) dpf_workflow.SetOutputMesh(display_mesh.outputs.getmesh()) dpf_workflow.SetOutputContour(s) dpf_workflow.Record('wf_id', False) this.WorkflowId = dpf_workflow.GetRecordedId()
And this is how the result looks like:
0