Export results during a DOE
I'd like to export temperature results for each DP of a DOE analysis. How can I do that?
Best Answer
-
The Python Code object can be used for this.
First, insert a temperature result that will be used for all DPs:
Then, insert a Python Code object that will be triggered after post:
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 property_templates.set_ext_api(ExtAPI) 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 Returns: 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 Returns: 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): self.name = 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, self.name) for prop in scoping_prop.GetGroupedProps(): self.provider.AddProperty(prop) 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() else: 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](self.name + "/" + name, self.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 self.provider.AddProperty(prop) return prop def __init__(self): pass 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 self.prop_groups.add(name) 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_list.append(prop.Name) self.prop_map[prop.Name] = prop #end region """ Reload the properties at the end to make sure the class definition is executed before instantiation """ reload_props()
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 ''' try: 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): os.makedirs(UserDir) return UserDir except: 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" temp_result.ExportToTextFile(os.path.join(user_files,file_name))
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:
When the DPs are updated, the exported files will be saved to the user_files directory:
Finally, some 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
2
Answers
-
Out of curiosity, any reason not to use native function to get user_files dir?
def user_files_directory(): user_files = '' if ExtAPI.Context == 'Project': user_files = GetUserFilesDirectory() elif ExtAPI.Context == 'Mechanical': import wbjn user_files = wbjn.ExecuteCommand(ExtAPI, "returnValue(GetUserFilesDirectory())") return user_files
0 -
Hi @Pavel , your function for gettting the userfiles directory will work just fine too. I just reused some code I had lying around, that dates back to before
GetUserFilesDirectory()
was implemented, is all.1