Gradient-Based Optimization (Parametric Studies)
In addition to evaluating performance, CFD can be a strong design tool that eliminates the need for a wind tunnel or a physical car to test (though of course this should always be validated with such testing). This document details how to use gradient-based optimization via parametric studies in ANSYS to supplement design decisions.
Imagine we are designing a front wing for the car. The first important design milestone is to establish the geometry of the airfoils, namely:
Chord lengths
AoAs
Overlap distances
Step heights
This is a relatively short list of variables to optimize for performance, however, further consideration quickly shows that optimization of these parameters can be very complicated.
We can use parametric studies within ANSYS to produce an optimization gradient that informs us which parameters to change, and iterate until we meet a certain goal.
It begins with a baseline, which is a randomly chosen starting point that serves as a control iteration. From there, each subsequent iteration adjusts only one value; two iterations are needed to explore both increases and decreases in values.
Due to some wacky shit with ANSYS, each iteration is not reinitialized; rather, every design point uses DP0’s initialization. This causes errors in the subsequent iterations, which can be proven by running independent studies under the same parameters.
To circumvent this, use a journal file that forces ANSYS to refresh each step and then manually reinitialize and runs every simulation. This takes longer, but yields accurate outputs. An example journal file that can be used is below:
# encoding: utf-8
# 2024 R2
SetScriptVersion(Version="24.2.133")
NUM_DP=21 #number of design points to run
for i in range(NUM_DP):
designPoint1 = Parameters.GetDesignPoint(Name=str(i)) #Figuring out which design point we want to run based on i value in loop
Parameters.SetBaseDesignPoint(DesignPoint=designPoint1) #Setting said design point as current
system1 = GetSystem(Name="FFF") #idk what this does
geometry1 = system1.GetContainer(ComponentName="Geometry") #Opening geometry tab, updating/refreshing, and then closing
geometry1.Edit()
geometry1.Exit()
meshComponent1 = system1.GetComponent(Name="Mesh") #Opening mesh tab, updating/refreshing, and then closing
meshComponent1.Refresh()
mesh1 = system1.GetContainer(ComponentName="Mesh")
mesh1.Edit()
mesh1.Exit()
meshComponent1.Update(AllDependencies=True)
setupComponent1 = system1.GetComponent(Name="Setup") #Opening setup
setupComponent1.Refresh()
setup1 = system1.GetContainer(ComponentName="Setup")
fluentLauncherSettings1 = setup1.GetFluentLauncherSettings()
fluentLauncherSettings1.SetEntityProperties(Properties=Set(EnvPath={}))
setup1.Edit()
setup1.SendCommand(Command='(cx-gui-do cx-activate-tab-index "NavigationPane*Frame1(TreeTab)" 0)(cx-gui-do cx-activate-tab-index "NavigationPane*Frame1(TreeTab)" 1)')
setup1.SendCommand(Command='/file/set-tui-version "24.2"(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Initialization"))')
setup1.SendCommand(Command='(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Initialization"))(cx-gui-do cx-activate-item "NavigationPane*Frame2*Table1*List_Tree2")')
setup1.SendCommand(Command='(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Initialization"))')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "Solution Initialization*Table1*Frame12*PushButton2(Initialize)")')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "Solution Initialization*Table1*Frame13*PushButton2(FMG)")')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "FMG Initialization*PanelButtons*PushButton4(Calculate)")')
setup1.SendCommand(Command='(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Run Calculation"))')
setup1.SendCommand(Command='(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Run Calculation"))(cx-gui-do cx-activate-item "NavigationPane*Frame2*Table1*List_Tree2")')
setup1.SendCommand(Command='(cx-gui-do cx-set-list-tree-selections "NavigationPane*Frame2*Table1*List_Tree2" (list "Solution|Run Calculation"))')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "Run Calculation*Table1*Table6(Solution Advancement)*Table1*PushButton1(Calculate)")')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "Information*OK")')
setup1.SendCommand(Command='(cx-gui-do cx-activate-item "MenuBar*FileMenu*Close Fluent")')
# Improvements to be made:
# -Gives error if this script tries to set a DP to current that is already current. Have an if statement check for this.
# -Rn if the # of design points changes I have to come back and edit the range of the for loop. Would be nice to have something that automatically sets the range based off the number of design points.
After running a parametric study, first choose new baseline step and overlap values, as they will dictate the angles and chord lengths of the airfoils. Pick values that yield an overall improvement toward target values. Make sure that the new baseline is within the rules envelope.