Getting started with DPF in Mechanical
Answers
-
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.
0 -
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)
0 -
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)
0 -
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:
0 -
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))
0 -
To get plotted results on several time steps, you'll have to do two things:
- Use a time scoping as before to define several time steps
- In the Python Result object, uncomment the "table_retrieve_result" function.
This will enable you to do a RMB click on tabular data and select at which time step you want to see the result:
0 -
The last thing that you might be interested in doing is customizing the detail's view of the Python Result:
Here I've defined:- a user input that will scale Sx+SY on the named selection by the specified amount
- a user output that can be parametrized and will display the max value on the plot.
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()
0