How to assess the maximum stress range for a fatigue assessment when there are several load cases?

Jan Henrik Hurrelbrink
Jan Henrik Hurrelbrink Member, Employee Posts: 3
First Anniversary Ansys Employee First Comment Photogenic
✭✭✭
edited June 2023 in Structures

This might be a trivial task if there is a manageable number of load cases. Once the load case number is increasing and/or the data is sitting in different result files the effort for doing it may get time consuming.

Tagged:

Answers

  • Jan Henrik Hurrelbrink
    Jan Henrik Hurrelbrink Member, Employee Posts: 3
    First Anniversary Ansys Employee First Comment Photogenic
    ✭✭✭
    edited May 2023

    One way would be via a python result object in conjunction with the Data Processing Framework module, to fetch the according data and evaluate the maximum stress range over all time points. Further on, it is possible to reference other result files to include these within the evaluation, assuming they are utilizing the same mesh (Node IDs). This example will perform the stress range based on maximum and minimum principal stress.

    To enable this, you will need to include a Python Result Object >>>

    The object itself has a main script and a property provider (e.g. enabling scoping methods) 

    After inserting the object, the property provider script was altered to include a geometry scoping possibility which may reduce the time needed for evaluation. The function reload_props() was replaced by following script 

    def reload_props():
        this.PropertyProvider = None
        provider = Provider()
        group_one = provider.AddGroup("Group 1")
        scoping_prop = group_one.AddProperty("Scoping Property", "Scoping", "property_templates")
        this.PropertyProvider = provider
    

    Reload the properties for that object

    Then you should be able to select a geometric entity for that object.

    Afterwards replace the whole default main script with the following python snippet, whereas the part of the individual result file reference may need some adjustment.

     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
        
        #Utilizing geometry scoping > time reduction in calculation time
        scoping_refs = this.GetCustomPropertyByPath("Group 1/Scoping Property/Geometry Selection").Value
        mech_dpf.setExtAPI(ExtAPI)
        nodes_loc = mech_dpf.GetNodeScopingByRefId(scoping_refs)
        
        #refering to the individual rst files
        dataSource_a = dpf.DataSources()
        dataSource_a.SetResultFilePath(analysis.ResultFileName) #the result file where the py result object was added to
        dataSource_b = dpf.DataSources()
        dataSource_b.SetResultFilePath(r'C:\...Mechanical\pyResultObject\StressRange_2023R1_files\dp0\SYS\MECH\file.rst')
        #result file list which will be looped thru
        data = [dataSource_a,dataSource_b] # [dataSource_a,dataSource_b,dataSource_c, ...]
        
        maxprin_fields = []
        minprin_fields = []
    
    
        #function to convert units if needed
        def convert_unit(field,unit):
            op = dpf.operators.math.unit_convert()
            op.inputs.unit_name.Connect(unit)
            op.inputs.entity_to_convert.Connect(field)
            converted_field = op.outputs.converted_entity.GetDataT1()
            return converted_field
    
    
        #loop thru the individual result files
        for i,rst in enumerate(data):
            op = dpf.operators.metadata.time_freq_provider() # operator instanciation
            op.inputs.data_sources.Connect(rst)
            my_time_freq_support= op.outputs.time_freq_support.GetData() #get the time points in the result file
            # read in min max principal stress for all time points
            stress_prin1 = dpf.operators.result.stress_principal_1(data_sources=rst,mesh_scoping=nodes_loc)
            stress_prin3 = dpf.operators.result.stress_principal_3(data_sources=rst,mesh_scoping=nodes_loc)
    
    
            #loop thru the time points
            for j,time in enumerate(my_time_freq_support.TimeFreqs.Data):
                stress_prin1.inputs.time_scoping.Connect(time)
                stress_prin3.inputs.time_scoping.Connect(time)
                stress_prin1.inputs.mesh_scoping.Connect(nodes_loc)
                stress_prin3.inputs.mesh_scoping.Connect(nodes_loc)
                field_container_max = stress_prin1.outputs.fields_container.GetData()
                field_container_min = stress_prin3.outputs.fields_container.GetData()
                #create list of min and max stress
                maxprin_fields.append(field_container_max[0])
                minprin_fields.append(field_container_min[0])
            
            #create a field container holding all the data 
            max_prin_field_container = dpf.FieldsContainerFactory.OverTimeFreqFieldsContainer(maxprin_fields)
            min_prin_field_container = dpf.FieldsContainerFactory.OverTimeFreqFieldsContainer(minprin_fields)
    
    
        # check unit systems if there is a mismatch the first entry will be utilized for converting
        count=max_prin_field_container.FieldCount
        for i in range(0,count):
            if i ==0:
                unit = max_prin_field_container[i].Unit
            else:
                if max_prin_field_container[i].Unit != unit:
                    max_prin_field_container[i]=convert_unit(max_prin_field_container[i],unit)
                if min_prin_field_container[i].Unit != unit:
                    min_prin_field_container[i]=convert_unit(min_prin_field_container[i],unit)
    
    
        #fetch the min and max over all time points of all provided result files
        op = dpf.operators.min_max.min_max_by_entity() # operator instanciation
        op.inputs.fields_container.Connect(max_prin_field_container)
        my_field_max = op.outputs.field_max.GetData()
        op.inputs.fields_container.Connect(min_prin_field_container)
        my_field_min = op.outputs.field_min.GetData()
        
        #evaluate the range > delta_sigma =  simga_1 - simga_3
        stress_range = dpf.operators.math.minus(fieldA=my_field_max,fieldB=my_field_min)
    
    
        ############### Plotting
        dpf_workflow = dpf.Workflow()
        dpf_workflow.Add(stress_range)
        dpf_workflow.SetOutputContour(stress_range.outputs.field.GetData(),dpf.enums.GFXContourType.GeomFaceScoping)
        dpf_workflow.Record('wf_id', True)
        this.WorkflowId = dpf_workflow.GetRecordedId()
    

    The last step would be to connect the script followed by ‘Evaluate All Results’

    The outcome will look like this S1(1072.064) – S3(-545.344) =delta_stress (1617.408)