Skip to main content

Exporting results during a DOE | 01.30.2023

This week’s script tip comes from our very own Pernelle Marone-Hitz, Lead Application Engineer at Ansys. In this tip, we’ll be exploring how to export temperature results for each DP of a DOE analysis.

The Python Code object can be used for this.

First, insert a temperature result that will be used for all DPs:

Steady-state thermal (AS) solution (A6)
Steady-State Thermal (AS), Solution (A6)

Then, insert a Python Code object

Python Code Insert
Python Code Insert

this will be triggered after post:

Details of “Python Code”, Definition table
Details of “Python Code”, Definition table

Modify the Property Provider so that this object uses an input parameter:

def reload_props():
    this.PropertyProvider = None
    # Create the property instance
    provider = Provider()
    # Create a group named Group 1.
    group = provider.AddGroup("Parameter")
    # Create a property with control type Expression and a property with control type Double, and add it to the Group 1
    double_prop = group.AddProperty("DPValue", Control.Double)
    double_prop.CanParameterize = True
    double_prop.ParameterType = ParameterType.Input
    this.PropertyProvider = provider

# region Property Provider Template
from Ansys.ACT.Mechanical.AdditionalProperties import PropertyProviderAdapter
from Ansys.ACT.Mechanical.AdditionalProperties import *

The property_templates module is located in %awp_root212%\aisol\DesignSpace\DSPages\Python\mech_templates
from mech_templates import property_templates


class Provider(Ansys.ACT.Interfaces.Mechanical.IPropertyProvider):
    Provider template that implements IPropertyProvider to demonstrate the usage of IPropertyProvider.
    It provides helper methods and classes that manage properties that can be dynamically added to an object.
    # region These are callbacks that as a user you may want to modify to get specific behavior
    def IsValid(self, prop):
        Called when checking the validity of a property, with the property instance.

        # for double property use the ValidRange property to check validity
        if(isinstance(prop, DoubleProperty)):
            return prop.ValidRange[0] <= prop.Value and prop.ValidRange[1] >= prop.Value
        return True
    def IsReadOnly(self, prop):
        Called when checking if a property should be readonly, with the property instance.

        return False
    def IsVisible(self, prop):
        Called when checking if a property should be visible, with the property instance.

        return True
    def SetValue(self, prop, val):
        Allows you to override the setter of the Value property on the property instance. 
        Keyword Arguments:
            prop -- property of which the value is being set
            val -- the value that was set
            The value that the Value property should be set to
        return val

    def GetValue(self, prop, val):
        Allows you to override the getter of the Value property on the property instance. 
        Keyword Arguments:
            prop -- property of which the value is being set
            val -- current value of the Value property
            The value that the getter on the internal value should return
        return val
    # endregion   
    # structures that hold property instances
    prop_list = []
    prop_map = {}
    prop_groups = set()

    class __AnsGroup():
        Helper group class to group properties, and provides methods to add properties to groups.
        provider = None
        def __init__(self,name=None, provider=None):
   = name
            self.provider = provider
        def __AddScopingProperty(self, name):
            Adds a scoping property with a given name to this group.
            Keyword Arguments : 
                name -- unique name for the scoping property
            scoping_prop = property_templates.ScopingProperty(name,
            for prop in scoping_prop.GetGroupedProps():
            return scoping_prop.GetGroupedProps()
        def AddProperty(self, name=None, prop_control=None, module_name=None):
            Creates an instance of the property and connects delgates in 
            the associated Property Propvider.

            Keyword Arguments : 
                name -- unique name for the scoping property
                prop_control -- one of the built in controls, or extended controls
                module_name -- module where the control is defined

            #special case for scoping property
            if(prop_control == "Scoping" and module_name == "property_templates"):
                return self.__AddScopingProperty(name)
            #if no module_name is passed, use the globals in current module
            #that has the built in controls imported
            prop_mod_globals = None
            if(module_name != None):
                if(module_name not in globals()):
                    raise Exception("Unknown module : " + module_name)
                prop_mod_globals = globals()[module_name].get_globals()
                prop_mod_globals = globals()
            #class name is built based on control + "Property"
            #    Double - > DoubleProperty
            prop_class_name = str(prop_control) + "Property"
            if(prop_class_name not in prop_mod_globals):
                raise Exception("Unknown property class : " + prop_class_name)
            #instantiate the property based on module and class name
            prop = prop_mod_globals[prop_class_name]( + "/" + name,
            if(prop == None):
                raise Exception("Issue while creating the property instance.")
            #set the delegates to property provider functions
            prop.IsValidCallback = self.provider.IsValid
            prop.IsReadOnlyCallback = self.provider.IsReadOnly
            prop.IsVisibleCallback = self.provider.IsVisible
            prop.GetValueCallback = self.provider.GetValue
            prop.SetValueCallback = self.provider.SetValue

            #as a default make the property name the property display name
            prop.DisplayName = name
            #add property to the provider
            return prop
    def __init__(self):

    def GetProperties(self):
        Returns a list of properties in the order that they were added to the property provider. 
        return [self.prop_map[propName] for propName in self.prop_list]
    def AddGroup(self, name=None):
        Creates an instance of helper group class and returns it.
        if name in self.prop_groups:
            raise Exception("Group with name " + name + " already exists, please use a unique group name.")
        #keep groups names so we can make sure no duplicate groups are added
        return self.__AnsGroup(name, self)
    def AddProperty(self, prop):
        Method used by the helper group class to add the property to the data-structure holding
        the property instances.
        if(prop.Name in self.prop_map):
            raise Exception("Property name must be unique, property with name '" + prop.Name + "' already exisits.")
        self.prop_map[prop.Name] = prop
#end region

Reload the properties at the end to make sure the class definition is executed before instantiation

As for the script part, two methods are used. One to grab the user_files directory, one called during execution to grab the existing temperature result and export the data to a csv file:

import os

def GetUserFileFolder(analysis):
        Return UserDir: path of the folder
        WorkDir = analysis.WorkingDir
        UserDir = os.path.dirname(WorkDir)
        for i in range(3):
            UserDir = os.path.dirname(UserDir)
        UserDir = os.path.join(UserDir, 'user_files')
        if not os.path.exists(UserDir):
        return UserDir
        ExtAPI.Log.WriteMessage("Error : Exception in GetUserFileFolder()")
        return None

def after_post(this, solution):# Do not edit this line
    temp_result = ExtAPI.DataModel.Project.Model.GetChildren(DataModelObjectCategory.TemperatureResult,True)[0]
    user_files = GetUserFileFolder(solution.Parent)
    DPValue = this.GetCustomPropertyByPath("Parameter/DPValue").Value
    file_name = "TemperatureResult_" + str(DPValue) + ".csv"

From the parameter set, define a value for the DPValue parameter (defined in the properties provider) so that each export file has a different name:

 Table of design points
Table of design points

When the DPs are updated, the exported files will be saved to the user_files directory:

Temperature Results csv file
Temperature Results csv file

Finally, some other useful tips:

  • For the exported file to include nodal location, from Mechanical, go to File / Options / Export / Include Node Location.
  • For the Python code object to work during a DOE, from the WB project schematic, go to Tools / Options / Mechanical / Connect run Python code objects when Mechanical is launched