How to get a safety factor result in a model with a custom yield limit for specific elements?
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.
Best 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()
2