Can you provide a quick Getting Started with DPF in Mechanical?
This post will be comprised of several examples with increasing difficulty. The starting point is to access the Mechanical Scripting Console: And then generate the DPF documentation by executing the following code:
import mech_dpf import Ans.DataProcessing as dpf my_output_path = (r"D:\DPF\Resources") op = dpf.operators.utility.html_doc() op.inputs.output_path.Connect(my_output_path) op.Run()
This will generate a .html file in the specified folder. Use any web browser to open this file.
The second step is to understand how to open a result file and define the data sources. Check this post for further info: https://discuss.ansys.com/discussion/3075/opening-result-files-with-dpf-defining-datasources/p1?new=1 In the examples shown in the above post, we are retrieving the normal SX stress on node #1. Let's complexify things a little bit and compute the sum of SX + SY on node 1. We'll use three operators: one to retrieve SX, one to retrieve SY, and one to sum.
import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) #Get path to result file analysis = ExtAPI.DataModel.Project.Model.Analyses[0] filepath = analysis.ResultFileName #Data sources dataSources = dpf.DataSources() dataSources.SetResultFilePath(filepath) #Scoping scoping = dpf.Scoping() scoping.Ids = [1] scoping.Location = 'Nodal' #Stress X direction stressXOp = dpf.operators.result.stress_X() stressXOp.inputs.data_sources.Connect(dataSources) stressXOp.inputs.mesh_scoping.Connect(scoping) sX = stressXOp.outputs.fields_container.GetData() #Stress Y direction stressYOp = dpf.operators.result.stress_Y() stressYOp.inputs.data_sources.Connect(dataSources) stressYOp.inputs.mesh_scoping.Connect(scoping) sY = stressYOp.outputs.fields_container.GetData() #Add Operator addOp = dpf.operators.math.add() addOp.inputs.fieldA.Connect(sX) addOp.inputs.fieldB.Connect(sY) addSxSy = addOp.outputs.field.GetData() print(addSxSy.Data)
What if we want to use a named selection instead of grabbing the node number? We'll have to use another operator, to define a scoping on a named selection. Important note: when sent to the Mechanical solver, named selection will be in capital letters. So if you have a NS named "my_ns", to retrieve it in DPF, you'll have to use "MY_NS".
import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) #Get path to result file analysis = ExtAPI.DataModel.Project.Model.Analyses[0] filepath = analysis.ResultFileName #Data sources dataSources = dpf.DataSources() dataSources.SetResultFilePath(filepath) # Model model=dpf.Model(dataSources) print(model.AvailableNamedSelections) #Scoping on named selection scoping_on_ns = dpf.operators.scoping.on_named_selection() scoping_on_ns.inputs.requested_location.Connect('Nodal') scoping_on_ns.inputs.named_selection_name.Connect('NODE1') scoping_on_ns.inputs.data_sources.Connect(dataSources) my_mesh_scoping = scoping_on_ns.outputs.mesh_scoping.GetData() #Stress X direction stressXOp = dpf.operators.result.stress_X() stressXOp.inputs.data_sources.Connect(dataSources) stressXOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sX = stressXOp.outputs.fields_container.GetData() #Stress Y direction stressYOp = dpf.operators.result.stress_Y() stressYOp.inputs.data_sources.Connect(dataSources) stressYOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sY = stressYOp.outputs.fields_container.GetData() #Add Operator addOp = dpf.operators.math.add() addOp.inputs.fieldA.Connect(sX) addOp.inputs.fieldB.Connect(sY) addSxSy = addOp.outputs.field.GetData() print(addSxSy.Data)
What if we want to plot this sum on the model ? Just copy/paste the code to a Python Result objects and make a few adaptations (basically to define what to plot) as follows:
def define_dpf_workflow(analysis): import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) #Get path to result file filepath = analysis.ResultFileName #Data sources dataSources = dpf.DataSources() dataSources.SetResultFilePath(filepath) # Model model=dpf.Model(dataSources) #Scoping on named selection scoping_on_ns = dpf.operators.scoping.on_named_selection() scoping_on_ns.inputs.requested_location.Connect('Nodal') scoping_on_ns.inputs.named_selection_name.Connect('MY_NS') scoping_on_ns.inputs.data_sources.Connect(dataSources) my_mesh_scoping = scoping_on_ns.outputs.mesh_scoping.GetData() #Stress X direction stressXOp = dpf.operators.result.stress_X() stressXOp.inputs.data_sources.Connect(dataSources) stressXOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sX = stressXOp.outputs.fields_container.GetData() #Stress Y direction stressYOp = dpf.operators.result.stress_Y() stressYOp.inputs.data_sources.Connect(dataSources) stressYOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sY = stressYOp.outputs.fields_container.GetData() #Add Operator addOp = dpf.operators.math.add() addOp.inputs.fieldA.Connect(sX) addOp.inputs.fieldB.Connect(sY) addSxSy = addOp.outputs.field.GetData() dpf_workflow = dpf.Workflow() dpf_workflow.Add(addOp) dpf_workflow.SetOutputContour(addOp) dpf_workflow.Record('wf_id', False) this.WorkflowId = dpf_workflow.GetRecordedId()
The plot will be on the named selection:
By default, DPF will only consider the results in the last time step. If you analysis contains several time steps, you'll have to define a time scoping and say at which time steps you want to retrieve/compute data. Using our example, the script becomes:
import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) #Get path to result file analysis = ExtAPI.DataModel.Project.Model.Analyses[0] filepath = analysis.ResultFileName #Data sources dataSources = dpf.DataSources() dataSources.SetResultFilePath(filepath) # Model model=dpf.Model(dataSources) print(model.TimeFreqSupport) # Using time scopings time_scoping = dpf.Scoping() number_sets = model.TimeFreqSupport.NumberSets time_scoping.Ids = range(1, number_sets+1) #Scoping on named selection scoping_on_ns = dpf.operators.scoping.on_named_selection() scoping_on_ns.inputs.requested_location.Connect('Nodal') scoping_on_ns.inputs.named_selection_name.Connect('NODE1') scoping_on_ns.inputs.data_sources.Connect(dataSources) my_mesh_scoping = scoping_on_ns.outputs.mesh_scoping.GetData() #Stress X direction stressXOp = dpf.operators.result.stress_X() stressXOp.inputs.data_sources.Connect(dataSources) stressXOp.inputs.mesh_scoping.Connect(my_mesh_scoping) stressXOp.inputs.time_scoping.Connect(time_scoping) sX = stressXOp.outputs.fields_container.GetData() #Stress Y direction stressYOp = dpf.operators.result.stress_Y() stressYOp.inputs.data_sources.Connect(dataSources) stressYOp.inputs.mesh_scoping.Connect(my_mesh_scoping) stressYOp.inputs.time_scoping.Connect(time_scoping) sY = stressYOp.outputs.fields_container.GetData() #Add Operator addOp = dpf.operators.math.add_fc() addOp.inputs.fields_container1.Connect(sX) addOp.inputs.fields_container2.Connect(sY) addSxSy = addOp.outputs.fields_container.GetData() print(addSxSy) print('Value at first step is: ' + str(addSxSy[0].Data)) print('Value at second step is: ' + str(addSxSy[1].Data))
To get plotted results on several time steps, you'll have to do two things:
The last thing that you might be interested in doing is customizing the detail's view of the Python Result: Here I've defined:
This is achieved by modifying the Property Provider of the Python Result: as follows:
def reload_props(): this.PropertyProvider = None # Create the property instance provider = Provider() # Create a group named Group 1. group = provider.AddGroup("User inputs and outputs") scale_value = group.AddProperty("Scale Value", Control.Double) max_result = group.AddProperty("Max Res Value", Control.Double) max_result.CanParameterize = True max_result.ParameterType = ParameterType.Output this.PropertyProvider = provider
The code in the script itself will be:
def define_dpf_workflow(analysis): import mech_dpf import Ans.DataProcessing as dpf mech_dpf.setExtAPI(ExtAPI) #Get path to result file analysis = ExtAPI.DataModel.Project.Model.Analyses[0] filepath = analysis.ResultFileName #Data sources dataSources = dpf.DataSources() dataSources.SetResultFilePath(filepath) # Model model=dpf.Model(dataSources) #Scoping on named selection scoping_on_ns = dpf.operators.scoping.on_named_selection() scoping_on_ns.inputs.requested_location.Connect('Nodal') scoping_on_ns.inputs.named_selection_name.Connect('MY_NS') scoping_on_ns.inputs.data_sources.Connect(dataSources) my_mesh_scoping = scoping_on_ns.outputs.mesh_scoping.GetData() #Stress X direction stressXOp = dpf.operators.result.stress_X() stressXOp.inputs.data_sources.Connect(dataSources) stressXOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sX = stressXOp.outputs.fields_container.GetData() #Stress Y direction stressYOp = dpf.operators.result.stress_Y() stressYOp.inputs.data_sources.Connect(dataSources) stressYOp.inputs.mesh_scoping.Connect(my_mesh_scoping) sY = stressYOp.outputs.fields_container.GetData() #Add Operator addOp = dpf.operators.math.add() addOp.inputs.fieldA.Connect(sX) addOp.inputs.fieldB.Connect(sY) addSxSy = addOp.outputs.field.GetData() # Scale scale_value = this.GetCustomPropertyByPath("User inputs and outputs/Scale Value").Value scale_op = dpf.operators.math.scale() scale_op.inputs.field.Connect(addSxSy) scale_op.inputs.ponderation.Connect(scale_value) scaled_res = scale_op.outputs.field.GetData() # Get max value over field min_max = dpf.operators.min_max.min_max() # operator instantiation min_max.inputs.field.Connect(scaled_res) my_field_max = min_max.outputs.field_max.GetData() my_max = my_field_max.Data[0] # Output this.GetCustomPropertyByPath("User inputs and outputs/Max Res Value").Value = my_max # Plot dpf_workflow = dpf.Workflow() dpf_workflow.Add(scale_op) dpf_workflow.SetOutputContour(scale_op) dpf_workflow.Record('wf_id', False) this.WorkflowId = dpf_workflow.GetRecordedId()
I am trying to find maximum principal stress in named selection. I found this reference for max operator (https://dpf.docs.pyansys.com/version/stable/operator_reference_load.html). Do I need to import additional libraries for this? When I added lines like below, I get error "Traceback (most recent call last): TypeError: LinkableOutput[Field] is not callable' for line "s1_Max = opMax.outputs.field_min()". #Maximum Principal Stress stress1Op = dpf.operators.result.stress_principal_1() stress1Op.inputs.data_sources.Connect(dataSources) stress1Op.inputs.mesh_scoping.Connect(my_mesh_scoping) s1 = stress1Op.outputs.fields_container.GetData()
opMax = dpf.operators.min_max.min_max_by_entity() # operator instantiation opMax.inputs.fields_container.Connect(s1) s1_Max = opMax.outputs.field_min() print(s1_Max.Data)
@Hrishikesh.Panchanwagh , your question is not related to the topic of the post. Please create a new post for this. Thank you