Get successive elements with max stress in depth of structure

Pernelle Marone-Hitz
Pernelle Marone-Hitz Member, Moderator, Employee Posts: 734
First Comment First Anniversary Ansys Employee Solution Developer Community of Practice Member
edited June 2023 in Structures

I'd like to select an element, and based on that starting point get the successive N elements with max stress in the depth of the solid body.

Tagged:

Answers

  • Pernelle Marone-Hitz
    Pernelle Marone-Hitz Member, Moderator, Employee Posts: 734
    First Comment First Anniversary Ansys Employee Solution Developer Community of Practice Member
    edited March 2023

    Here is an example of Python Result that :

    • allows the user to :
      • select an element "start_elem" on the surface of a solid body
      • define the number of in-depth layers that should be considered
    • calculates and plots a result as follow:
      • retrieve the stress on start_elem
      • select the elements connected to start_elem, but only the elements in the depth of the structure, and identify the element with max stress on the selected elements
      • iterate this procedure N number of times, N being the number of layers defined by the user
    • plot the identified elements and evaluate the average stress on these elements

    This is achieved by editing the Property Provider of the Python Result 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)
    
    
        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
    

    As a result, the properies of the Python Result should look like this:

    And the Script to use in 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)
        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
        
        # Retrieve Von Mises stress on elements
        s = dpf.operators.result.stress_von_mises()
        s.inputs.requested_location.Connect('Elemental')
        s.inputs.data_sources.Connect(dataSource)
    
        # 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.mesh_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.mesh_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.mesh_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()
    

    The starting element should be defined thanks to a named selection (and by providing the name of said NS in the property of the Python Result):

    With an standard equivalent stress plot as follows:

    This is how the Python Result will look like for 2 layers defined: