Get successive elements with max stress in depth of structure

Pernelle Marone-Hitz
Pernelle Marone-Hitz Member, Moderator, Employee Posts: 871
100 Answers 500 Comments 250 Likes First Anniversary
✭✭✭✭
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: 871
    100 Answers 500 Comments 250 Likes First Anniversary
    ✭✭✭✭
    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: