Postprocess stress over profile length for each layer of a solid composite model.

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

I have a solid composite model created in ACP.

I would like to post-process the stress over the profile length for each layer, so for example along the curved line that passes through these nodes:



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

    This is possible by using DPF and a Python Result. Below is a detailed explanation of how the example works and can be adapted.

    Defining named selections

    The code shared below uses a logic based on named selection names.

    A first named selection should provide the "base", so the surface from which the solid is extruded in ACP:

    A second named selection should provide the extrusion direction:

    Note - it is recommended to use CAPITAL letters to define the names of the named selections, as the named selections are always sent to the solver with capital letters and Python is case sensitive.

    Selection for the named selections and the layer number

    The user has to provide the name of the named selections, and the layer number for which they would like to do the postprocessing. This is done in the details' view of the Python Result object:

    To obtain such a details' view, the Property Provider of the Python Result object has to be modified as follows:

    def reload_props():
      this.PropertyProvider = None
      provider = Provider()   
      group1 = provider.AddGroup("Named Selections")
      base_ns = group1.AddProperty("Base face NS name", Control.Expression)
      extrusion_ns = group1.AddProperty("Extrusion face NS name", Control.Expression)   
      group2 = provider.AddGroup("Layer number")
      double_prop = group2.AddProperty("Layer number", Control.Double)
      this.PropertyProvider = provider

    Getting the logic to obtain the appropriate nodes for post-processing

    The logic is very similar to the MAPDL "ESLN/NSLE" logic, which selects nodes attached to the selected elements, and elements attached to the selected nodes.

    First we select all the nodes attached to the base face:

    Then we select all the elements attached to these nodes:

    Then the nodes attached to the selected elements:

    We keep a list of already selected nodes to filter out the nodes that have already been used:

    With this logic, we are able to get the nodes on a specific layer:

    Then, to obtain the path, we must only keep the nodes that also belong to the "extrusion" face:

    This is obtained by a simple boolean operation to get the intersection between two scopings.

    Obtaining a line display

    This is achieved by using the GFXContourType.GeomEdgeScoping option in the SetOutPutContour() method.

    Script for the Python Result

    The complete DPF script for the Python Result object is as follows:

    def post_started(sender, analysis):# Do not edit this line
    def define_dpf_workflow(analysis):
        import mech_dpf
        import Ans.DataProcessing as dpf
        dataSource = dpf.DataSources(analysis.ResultFileName)
        base_ns_name = str(this.GetCustomPropertyByPath("Named Selections/Base face NS name").Value)
        extrusion_ns_name = str(this.GetCustomPropertyByPath("Named Selections/Extrusion face NS name").Value)
        nb_layer = int(this.GetCustomPropertyByPath("Layer number/Layer number").Value)
        # Retrieve mesh 
        mesh=model.Mesh # whole mesh
        # Get first layer of nodes
        nodes_level_0 = dpf.operators.scoping.on_named_selection(named_selection_name=base_ns_name,data_sources=dataSource)
        used_node_ids = list(nodes_level_0.outputs.mesh_scoping.GetData().Ids)
        for layer_index in range(1,nb_layer):
            elements_level_0 = dpf.operators.scoping.transpose(mesh_scoping=nodes_level_0,meshed_region=mesh)
            nodes_level_1_all = dpf.operators.scoping.transpose(mesh_scoping=elements_level_0,meshed_region=mesh)
            nodes_level_1 = diff_nodes.outputs.scopingA_min_intersection
            node_ids_level_1 = list(nodes_level_1.GetData().Ids)
            node_ids_to_keep =  [id for id in node_ids_level_1 if id not in used_node_ids]
            added_used_node_ids = [id for id in node_ids_level_1 if id in used_node_ids]
            used_node_ids = used_node_ids + added_used_node_ids
            nodes_level_0 = dpf.Scoping()
            nodes_level_0.Ids = node_ids_to_keep
            used_node_ids = used_node_ids + node_ids_to_keep
        # Get nodes also part of EXTRUSION NS
        nodes_extrusion_ns = dpf.operators.scoping.on_named_selection(named_selection_name=extrusion_ns_name,data_sources=dataSource)
        # nodes_extrusion_ns.outputs.mesh_scoping.GetData().Ids
        nodes_path = diff_nodes_2.outputs.intersection
        # Equivalent stress on selected nodes
        seqv = dpf.operators.result.stress_von_mises()
        # Plot
        dpf_workflow = dpf.Workflow()
        dpf_workflow.Record('wf_id', False)
        this.WorkflowId = dpf_workflow.GetRecordedId()

    This is the result that is obtained: