How to get a safety factor result in a model with a custom yield limit for specific elements?

Javier Vique
Javier Vique Member, Employee Posts: 82
Name Dropper First Anniversary First Answer 25 Likes
✭✭✭✭
edited September 2023 in Structures

We want to get a safety factor result based on Von Mises stresses in a model where tensile yield strength must be based on elemental named selection.

Tagged:

Best Answer

  • Javier Vique
    Javier Vique Member, Employee Posts: 82
    Name Dropper First Anniversary First Answer 25 Likes
    ✭✭✭✭
    edited September 2023 Answer ✓

    This solution is based on a generic example, so it must be taken as a proof of concept and not a part of the official Ansys release (no maintenance guaranteed, use under customer responsibility).
    In the generic example, user defines 2 different elemental named selections called Weldlines1, Weldlines2. The tensile yield strength for the first one will be 2MPa and for the second one will be 1.5MPa. For the rest of the elements, the tensile yield strength will be 6MPa.
    In order to do this, we make use of Python Result. Inputs are introduced by parameters, including elemental named selections names and their yield strengths separated by commas, as well as the general yield strength, as shown below. Elements with generic yield strength must be defined in a named selection called "noweldlines". User can modify this in the DPF script.

    Here the code to be included in Property Provider:

    def reload_props():
        this.PropertyProvider = None
    
        # Create the property instance
        provider = Provider()
    
        # Create a group named Group 1.
        group = provider.AddGroup("Parameters")
    
        # Create a property with control type Expression and a property with control type Double, and add it to the Group 1
        reduced_Sy = group.AddProperty("Reduced Sy in MPa", Control.Expression)
        standard_Sy = group.AddProperty("Standard Sy in MPa", Control.Double)
        ns_name = group.AddProperty("Named Selection name", Control.Expression) # Expression is a string
    
        this.PropertyProvider = provider
    

    The DPF script is given below. The solution is based on elemental location (Elemental Mean in Mechanical). If Nodal or ElementalNodal locations are used, user must be careful how averaging is done, same way as "Average Across Body" in Mechanical. Additionally, for those values higher than 15, maximum value is set to 15, as it does Stress Tool in Mechanical.

    def post_started(sender, analysis):# Do not edit this line
        define_dpf_workflow(analysis)
    
    def define_dpf_workflow(analysis):
        import mech_dpf
        import Ans.DataProcessing as dpf
        mech_dpf.setExtAPI(ExtAPI)
    
        # Here the functions that get VonMises stress and scale them by reduced Sy value
        def weldline_fc(my_data_sources,my_time_scoping,weldline,scale_weldline):
            s_eqv_op_weldline = dpf.operators.result.stress_von_mises()
            s_eqv_op_weldline.inputs.requested_location.Connect('Elemental')
            s_eqv_op_weldline.inputs.data_sources.Connect(my_data_sources)
            s_eqv_op_weldline.inputs.time_scoping.Connect(my_time_scoping)
            s_eqv_op_weldline.inputs.mesh_scoping.Connect(weldline)
    
            s_eqv_op_weldline_inv = dpf.operators.math.invert_fc()
            s_eqv_op_weldline_inv.inputs.fields_container.Connect(s_eqv_op_weldline.outputs.fields_container.GetData())
    
            scale_op_weldline = dpf.operators.math.scale_fc()
            scale_op_weldline.inputs.fields_container.Connect(s_eqv_op_weldline_inv.outputs.fields_container.GetData())
            scale_op_weldline.inputs.ponderation.Connect(scale_weldline)
            scale_op_weldline_fc = scale_op_weldline.outputs.fields_container
            return scale_op_weldline_fc
    
        # List of field containers with weldlines data
        def create_weldline_fc_list(num_weldlines,DataSource,TimeScop,weldlines,scale_weldlines):
            weldline_fc_list = []
            [weldline_fc_list.append(weldline_fc(DataSource,TimeScop,weldlines[i],scale_weldlines[i])) for i in range(num_weldlines)]
            return weldline_fc_list
    
        # Units conversion
        def units_conversion(stress_units):
            import units
            convFactor = float(units.ConvertUnit(1.,"MPa",stress_units,"Stress"))
            return convFactor
    
        my_data_sources = dpf.DataSources(analysis.ResultFileName)
        model=dpf.Model(my_data_sources)
    
        # Input given in Parameters
        # Reduced Sy in MPa must be something like 2,2.5 including as many values as weldlines
        # Standard Sy in MPa must be something like 6 with just one value
        reduced = this.GetCustomPropertyByPath("Parameters/Reduced Sy in MPa").ValueString
        standard = this.GetCustomPropertyByPath("Parameters/Standard Sy in MPa").ValueString
    
        # Define time scoping (user might need to change it)
        my_time_scoping = dpf.Scoping()
        my_time_scoping.Ids = [1] # the first set
    
        # Input given in Parameters
        # Named Selections must be something like weldlines1,weldlines2 including as many values as weldlines   
        ns_names = this.GetCustomPropertyByPath("Parameters/Named Selection name").ValueString
        ns_names = ns_names.upper()
    
        weldlines=[]
        num_weldlines = len(ns_names.split(','))
    
        # Model must contain a named selection called noweldlines with all elements not affected by reduction
        noweldlines = model.GetNamedSelection('NOWELDLINES')
    
        # Get equivalent stresses on no weldlines
        s_eqv_op_noweld = dpf.operators.result.stress_von_mises()
        s_eqv_op_noweld.inputs.requested_location.Connect('Elemental')
        s_eqv_op_noweld.inputs.data_sources.Connect(my_data_sources)
        s_eqv_op_noweld.inputs.time_scoping.Connect(my_time_scoping)
        s_eqv_op_noweld.inputs.mesh_scoping.Connect(noweldlines)
    
        s_eqv_op_noweld_inv = dpf.operators.math.invert_fc()
        s_eqv_op_noweld_inv.inputs.fields_container.Connect(s_eqv_op_noweld.outputs.fields_container.GetData())
    
        # Stress units are verified and scale factor is converted into consistent units
        scale_weldlines = []
        convFactor = units_conversion(s_eqv_op_noweld.outputs.fields_container.GetData()[0].Unit)
    
        value_noweld = float(standard)*convFactor
        scale_noweld = value_noweld
    
        for i in reduced.split(','):
            value_weldline = float(i)*convFactor
            scale_weldlines.append(value_weldline)
    
        # Scale results on no weldlines
        scale_op_noweld = dpf.operators.math.scale_fc()
        scale_op_noweld.inputs.fields_container.Connect(s_eqv_op_noweld_inv.outputs.fields_container.GetData())
        scale_op_noweld.inputs.ponderation.Connect(scale_noweld)
        scale_op_noweld_fc = scale_op_noweld.outputs.fields_container
    
        # Get equivalent stresses on weldlines & scale them
        [weldlines.append(model.GetNamedSelection(i)) for i in ns_names.split(',')]
        weldline_fc_list = create_weldline_fc_list(num_weldlines,my_data_sources,my_time_scoping,weldlines,scale_weldlines)
    
    
        # Create combined result
        op = dpf.operators.utility.merge_fields_containers() # operator instantiation
        op.Connect(0,scale_op_noweld_fc.GetData())
        [op.Connect(j+1,weldline_fc_list[j].GetData()) for j in range(num_weldlines)]
        op.outputs.merged_fields_container.GetData()[0].Unit = ''
    
        SafetyFactor = op.outputs.merged_fields_container.GetData()
        for x in SafetyFactor[0].Scoping.Ids:
            if SafetyFactor[0].GetEntityDataById(x)[0] > 15.0:
                SafetyFactor[0].UpdateEntityDataByEntityIndex(SafetyFactor[0].Scoping.IndexById(x),[15.0])
    
        op_f = dpf.operators.utility.extract_field()
        op_f.inputs.fields_container.Connect(SafetyFactor)
        op_f.inputs.indices.Connect([0])
    
        dpf_workflow = dpf.Workflow()
        dpf_workflow.Add(op_f)
        dpf_workflow.SetOutputContour(op_f,dpf.enums.GFXContourType.FEElementalScoping)
        dpf_workflow.Record('wf_id', True)
        this.WorkflowId = dpf_workflow.GetRecordedId()