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.
This post combines and adapts the code written in these two posts:
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 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: