Design Optimization Tutorials

Design Optimization Tutorial #1
Max L/D for steady flow

Intent: Demonstrate setup and execution of L/D maximization for steady flow case

This tutorial will describe how to set up and run a shape optimization to maximize the lift-to-drag ratio for steady inviscid flow over a wing at Mach 0.8, alpha=2 degrees. The same procedure applies for viscous/turbulent flow; the user just needs to change the solver inputs accordingly (and the grid/parameterization obviously). Inviscid flow is simply used here for efficiency purposes.

Note: the input data provided in the download files is for FUN3D Version 10.8 and higher and will not work with earlier versions

All of the grid and input files may be downloaded below. Note that the grids for this case are very coarse and are intended for demonstration, rather than accurate aerodynamic analysis. The geometry consists of a single inviscid ONERA M6 wing.

The user should be familiar with running the baseline flow solver.

The process is composed of three basic steps. First, the optimization driver is used to perform an analysis consisting of an evaluation of the surface parameterization, a movement of the volume grid to correspond to that new surface grid, and finally, a flow solution. The next operation demonstrated is using the optimization driver to perform a sensitivity analysis. In this case, the driver will perform an analysis as just described, followed by a flowfield adjoint solution and a mesh adjoint solution to obtain the sensitivity vector. The final portion of the demonstration will use the optimization driver to perform an actual design optimization, maximizing L/D for the baseline wing.

Compilation and linking

To perform design optimization, you must obtain at least one of the third-party optimization libraries covered in the third-party library section of the website (PORT, NPSOL, and/or KSOPT). Your FUN3D installation must be configured and built to use these libraries. If you attempt to run an optimization without building against the library you’re trying to use, the design driver will abort and tell you so. This demo is set up to run using PORT, although KSOPT or NPSOL could be used instead. Since this demo relies on MASSOUD parameterizations, you must also have a MASSOUD executable present in your path.

Files

Download (253 KB).

Set up the baseline directory tree and associated files

The first thing you’ll need to do is create a directory where you wish to run the design case, and go down into it.

mkdir Demo1
cd Demo1

The next step is to use the design driver to construct the directory tree that FUN3D will be expecting to see when it runs the design. Do this by running the driver in your current directory. Note the path in the command is the path to your FUN3D build directory, and the command line argument shown is to generate the directory structure for a single-point design. Enter the required inputs exactly as requested (watch for the single quotes and trailing slashes):

/path/to/your/built/FUN3D/Design/opt_driver --setup_design 1

It is also a good idea to keep the screen output handy, as it is a nice checklist for all of the files you have to have in place prior to starting a design.

Now if you look in your current directory, you will see that the design driver created a tree with several directories. The only ones we will worry about are the description.1 directory (where the baseline case files are stored and never modified during the run) and the ammo directory, where the main optimization is performed from.

First go into the description.1 directory and move the supplied tarfile into here, then untar it:

cd description.1
cp /path/to/tarfile/design_demo1.tar.gz .
gunzip design_demo1.tar.gz
tar xvf design_demo1.tar

You should see the following files extracted into your current (description.1) directory:

command_line.options
design.1
design.gp.1
design.usd.1
fun3d.nml
inviscid.fastbc
inviscid.fgrid
machinefile
massoud.1
move_gmres.input
rubber.data

Feel free to look at each file if you want (please do so, in order to get used to whats in them). Note the BC for the symmetry plane boundary is set to 3080 in the inviscid.fastbc file. This is essentially the same as a tangency boundary condition (3000), except that the code will constrain mesh movement on this boundary to occur in-plane. This is the recommended BC for symmetry planes during design optimization. If you need to use the usual symmetry BC (6662), get in touch for limitations.

The only files from the tar file that should need modifications are as follows. If you normally specify the machines to be used for MPI jobs via a machinefile, those machines will have to appear in machinefile . Also, look at the command line options for mpirun in the command_line.options file. If those are not what you typically use, then you will need to modify them appropriately. If you are running in a queue environment that automatically handles the number of processors and which machines you will be running on, simply set the number of command line options for mpirun to “0” and delete the options shown in the supplied file.

Next head over to the ammo directory. There you will find a template for the ammo.input file which controls the optimization settings. Edit the file and make it look like the following. Set your path to the base directory appropriately, and if your MPI implementation is executed using a command other than ‘mpirun’ (such as ‘mpiexec’), then include it as needed. Also, the current example is set up to run on 8 processors. Feel free to change this as desired, but the value you supply must be consistent with any ‘-np xxx’ MPI option you may have supplied in the command_line.options file above.

Number of processors to use
8
Optimization package
4
Base directory from which to run optimization
'/misc/work12/nielsen/Demo1'
Number of design points
1
Weights for each design point
1.0
Grid type for each design point
1
Operation to perform
1
Restart the optimization
0
MASSOUD (=1) or Bandaid (=2) DV's
1
Diagnostics flag
0
Maximum number of lo-fi functions per subproblem
20
Maximum number of lo-fi subproblem iterations
10
Relative convergence criterion for subproblem
1.e-5
Absolute feasibility tolerance for constraint violation
110.0
Number of Cp slices followed by pairs of boundary indices for slices
0
Boundary pairs for Cp slices
Number of bodies with spatial transforms
0
List of bodies with spatial transforms
Body grouping desired (0=no, 1=yes)
0
Use pparty instead of party (0=no, 1=yes)
0
Executable for running MPI programs
'mpirun'

Perform a baseline analysis using the design driver

Go into the ammo directory and edit the ammo.input file. Make sure that the “Operation to perform” input is set to 1, which corresponds to a single analysis at the baseline design variables.

Now enter the following command (if you are running in a queue environment, this is the command that should be placed in your job script):

./opt_driver --sleep_delay 5 > screen.output &

This will fire up the design driver (in the background because of the ampersand at the end of the command) and start to perform a baseline analysis at the initial design point given by the data in the rubber.data file. You can monitor the progress by watching the screen.output file:

tail -f screen.output

Simply hit control-C when you want to exit the tail command.

The first major process you will see go by is party being run to partition the supplied grid.

The next major process you will see is the execution of MASSOUD to evaluate the parameterization at the baseline design point. This is used to define the location of the surface grid.

The next major process (the first MPI process) is the design driver firing off an MPI job to perform a mesh movement. This step is moving the volume grid to conform to the surface grid that MASSOUD just evaluated. One thing to watch for during this step is the initial residual of the linear elasticity solution. It should be very small:

.
.
.
 Iter      Natural Err Est         Error Estimate      Restarts
    0   0.630827082615162E-16   0.000000000000000E+00         0
.
.
.

This indicates that the surface in the baseline volume grid did not need to be moved very much to conform to the baseline design variables. When you do the actual design optimization, you will see this value become some large number, indicating the current surface grid in the volume mesh does not line up with the MASSOUD-generated surface, and therefore the entire mesh will be relaxed into its new position using elasticity relations.

The last major process you will see go by is the flow solver. At the end of its execution, you should see the current value of the cost function:

Current value of function            1   176.932026381008

This is the value of the cost function specified in rubber.data at the baseline design variables. If you look at ../model.1/rubber.data, you should now see this value in the cost function field. The usual FUN3D flow solver output files are available in the ../model.1/Flow/ directory. Note that they are also backed up with baseline prefixes, since they will be overwritten at every design cycle during the optimization. If you plot the convergence of the baseline solve we just did using the baseline_hist.tec file, you should get a density residual and L/D convergence that looks something like the following. Note the baseline L/D of about 6.7.

That concludes the baseline analysis procedure. For this very coarse grid (2800 nodes) on 8 processors, this whole process should have taken roughly 30 seconds to complete, depending on your hardware, file system, the sleep_delay you specified, etc.

Perform a baseline sensitivity analysis using the design driver

In this step, we will use the design driver to perform a sensitivity analysis. Edit the ammo.input file in the ammo directory, and change the “Operation to perform” input to 2, which corresponds to a single sensitivity analysis at the baseline design variables.

As before, now enter the following command:

./opt_driver --sleep_delay 5 > screen.output &

This will fire up the design driver and start to perform a baseline sensitivity analysis at the initial design point given by the data in the rubber.data file. You can monitor the progress by watching the screen.output file.

First, you will see the entire analysis procedure go by as described above.

However, it will now be followed by a couple of additional steps. The first additional step will be a flowfield adjoint solution. This will be followed by another execution of MASSOUD, this time to evaluate the sensitivities of the surface grid location with respect to the design variables. Next you will see an execution of the code getgrad, which is forming the RHS of the mesh adjoint equation. Finally, you will see the mesh movement code fire up again; however, it is now running in a transposed manner to solve the mesh adjoint problem. Once the mesh adjoint is solved, the sensitivity analysis procedure is complete. This whole thing should have taken a minute or two, again depending on your hardware and sleep_delay, etc.

Now head over to the ../model.1/Adjoint directory and run Tecplot on the inviscid_hist.tec file. This file contains the convergence history for the flowfield adjoint solution. If you plot the first residual in the file (adjoint equation for continuity), you should see something like the following.

Note the asymptotic convergence is very similar to that of the flow solution. These plots can be used to help set the kickout levels for the flow and adjoint solvers. In general, the kickout levels will be different, since the flow residual scales with the local cell size and the adjoint residual scales with the cost function definition. Also, you typically don’t have to converge the adjoint residuals more than a couple orders of magnitude to get reasonable sensitivities for guiding the optimization.

At this point, all of the sensitivities of the cost function have been populated in the model.1/rubber.data file. Feel free to have a look.

We are now ready to attempt an actual design optimization.

Perform a design optimization using the design driver

Now we will do an actual design optimization. Edit the file ammo.input in the ammo directory and change the “Operation to perform” to “3”. This value will run an actual design.

As before, enter the following command:

./opt_driver --sleep_delay 5 > screen.output &

This will fire up the design driver, and now you will see many analyses and sensitivity analyses going by. You can monitor the progress by watching for the output file(s) specific to the optimizer you are using (see the section on Design), or you can also grep for the current value of the objective function in the screen output:

grep "Current value of function" screen.output

 Current value of function            1   176.932026381008
 Current value of function            1   177.821434761496
 Current value of function            1   129.220240226849
 Current value of function            1   190.673994593673
 Current value of function            1   103.748612712936
 Current value of function            1   121.518007254771
 Current value of function            1   98.7934308021444
 Current value of function            1   102.714510389471
 Current value of function            1   98.5477607150379
 Current value of function            1   99.1776531554900
 Current value of function            1   98.7862111858035
 Current value of function            1   98.6437947171463
 Current value of function            1   98.5874424655280
 Current value of function            1   98.5643494140112
 Current value of function            1   98.5550891920066
 Current value of function            1   98.5503535942488
 Current value of function            1   98.5483085431904
 Current value of function            1   98.5500261202103
 Current value of function            1   98.5495758146971
 Current value of function            1   98.5483346030665
 Current value of function            1   98.5473696197903

Note that in this grep, you will see the cost occasionally go up – these are points in the design space where the optimizer is trying various combinations of the design variables. But in general, the values should be coming down. You can also monitor the cost function field in ../model.1/rubber.data .

When the run finishes (about 5-10 minutes or so, give or take), your final cost function should be roughly 98.55. Since all flow solves were restarted from the previous solution, you can plot up the values in the file ../model.1/Flow/inviscid_hist.tec to reveal the history of the design. You should see something like this for the L/D ratio:

From the plot, you can see that L/D went from the baseline value of 6.7 to roughly 10.0 during the course of the design. The final values of the design variables are given in the ../model.1/rubber.data file.

After the design is complete, you can also animate a history of the surface geometry. Go into the ../model.1/Rubberize/surface_history directory. There you will find a Tecplot file for every body at every step of the optimization. Alternatively, in the Flow directory, you will find a file called movie.tec . This file is a concatenated history of the solutions on the surface throughout the course of the design. This animation of the grid colored by density was created using this file:

From here, you can slice geometries to look at and animate, etc. If you get fancy with the slicing output options in the flow solver, you can do stuff like that, too.

Basically that’s the main steps for doing adjoint-based design optimization with FUN3D…have some patience, and get in touch if you have problems. Good luck!

Design Optimization Tutorial #2
Max L/D for steady flow at two different Mach numbers

Intent: Demonstrate setup and execution of multipoint L/D maximization for steady flow case

This tutorial will describe how to set up and run a shape optimization to maximize the lift-to-drag ratio at two separate Mach numbers (0.6 and 0.8) for steady inviscid flow over a wing. The same procedure applies for viscous/turbulent flow; the user just needs to change the solver inputs accordingly (and the grid/parameterization obviously). Inviscid flow is simply used here for efficiency purposes.

The instructions shown here assume the user has gone through the prior design tutorials and understands the basics of how they work.

All of the grid and input files may be downloaded below. Note that the grids for this case are very coarse and are intended for demonstration, rather than accurate aerodynamic analysis. The geometry consists of a single inviscid ONERA M6 wing.

Compilation and linking

This demo is set up to run using PORT. Since this demo relies on MASSOUD parameterizations, you must also have a MASSOUD executable present in your path.

Files

Download (253 KB).

Download (253 KB).

Set up the baseline directory tree and associated files

The first thing you’ll need to do is create a directory where you wish to run the design case, and go down into it.

mkdir Demo2
cd Demo2

The next step is to use the design driver to construct the directory tree that FUN3D will be expecting to see when it runs the design. Do this by running the driver in your current directory. Note the path in the command is the path to your FUN3D build directory, and the command line argument shown is to generate the directory structure for a 2-point design. Enter the required inputs exactly as requested (watch for the single quotes and trailing slashes):

/path/to/your/built/FUN3D/Design/opt_driver --setup_design 2

If you look in your current directory, you will see that the design driver created a tree with several directories. The only ones we will worry about are the description.i directory (where the baseline case files are stored and never modified during the run) and the ammo directory, where the main optimization is performed from.

First go into the description.1 directory and move the supplied tarfile for design point #1 into here, then untar it.

cd description.1
cp /path/to/tarfile/design_demo2_point1.tar.gz .
gunzip design_demo1.tar.gz
tar xvf design_demo1.tar

Now do the same thing for the tar file for design point #2, placing the files into the description.2 directory. Modify the MPI/machinefile information in both description.i directories as in the previous tutorial.

Next head over to the ammo directory. There you will find a template for the ammo.input file which controls the optimization settings. Edit the file and make it look like the following. Set your path to the base directory appropriately, and if your MPI implementation is executed using a command other than ‘mpirun’ (such as ‘mpiexec’), then include it as needed. Also, the current example is set up to run on 8 processors. Feel free to change this as desired, but the value you supply must be consistent with any ‘-np xxx’ MPI option you may have supplied in the command_line.options file above.

Number of processors to use
8
Optimization package
4
Base directory from which to run optimization
'/misc/work12/nielsen/Demo2'
Number of design points
2
Weights for each design point
1.0
1.0
Grid type for each design point
1
1
Operation to perform
3
Restart the optimization
0
MASSOUD (=1) or Bandaid (=2) DV's
1
Diagnostics flag
0
Maximum number of lo-fi functions per subproblem
20
Maximum number of lo-fi subproblem iterations
10
Relative convergence criterion for subproblem
1.e-5
Absolute feasibility tolerance for constraint violation
110.0
Number of Cp slices followed by pairs of boundary indices for slices
0
Boundary pairs for Cp slices
Number of bodies with spatial transforms
0
List of bodies with spatial transforms
Body grouping desired (0=no, 1=yes)
0
Use pparty instead of party (0=no, 1=yes)
0
Executable for running MPI programs
'mpirun'

This input deck is going to use PORT to minimize the heuristic multi-point objective function defined to be the sum of the objective function specified in rubber.data in each of the 2 description.i directories. The points are equally weighted.

Perform a multi-point design optimization using the design driver

As before, enter the following command:

./opt_driver --sleep_delay 5 > screen.output &

This will fire up the design driver, and now you will see many analyses and sensitivity analyses going by, some for each design point. You can monitor the progress by watching the ../model.2/port.output file.

When the run finishes (about 20 minutes or so, give or take), your cost function shown in the PORT file should have gone down from roughly 373 to 231. Plotting up the ../model.1/Flow/inviscid_hist.tec and ../model.2/Flow/inviscid_hist.tec files reveals the following history for the L/D ratio at each Mach number:

For the Mach 0.60 design point, you can see that L/D went from the baseline value of 6.0 to roughly 9.6 during the course of the design. Similarly, L/D for the Mach 0.80 design point went from 6.7 to 8.9.

Design Optimization Tutorial #3
Lift-constrained drag minimization for DPW wing

Intent: Demonstrate setup and execution of lift-constrained drag minimization for steady flow case

This tutorial will describe how to set up and run a shape optimization to minimize drag subject to a lift constraint for turbulent flow.

The instructions shown here assume the user has gone through the prior design tutorials and understands the basics of how they work. The example shown here is considerably larger (1.8 million grid points) and is demonstrated on 256 processors.

All of the grid and input files may be downloaded below. The grid was originally developed for the 3rd AIAA Drag Prediction Workshop. The geometry is the “Wing 1” configuration, operating at a 0.50 lift coefficient.

Compilation and linking

This demo is set up to run using NPSOL. Since this demo relies on MASSOUD parameterizations, you must also have a MASSOUD executable present in your path.

Files

Download (124 MB).

Download (7.5 MB).

Set up the baseline directory tree and associated files

The first thing you’ll need to do is create a directory where you wish to run the design case, and go down into it.

mkdir Demo3
cd Demo3

The next step is to use the design driver to construct the directory tree that FUN3D will be expecting to see when it runs the design. Do this by running the driver in your current directory. Note the path in the command is the path to your FUN3D build directory, and the command line argument shown is to generate the directory structure for a single-point design. Enter the required inputs exactly as requested (watch for the single quotes and trailing slashes):

/path/to/your/built/FUN3D/Design/opt_driver --setup_design 1

If you look in your current directory, you will see that the design driver created a tree with several directories. The only ones we will worry about are the description.i directory (where the baseline case files are stored and never modified during the run) and the ammo directory, where the main optimization is performed from.

First go into the description.1 directory and move the first supplied tarfile (the big one containing the grid from the DPW-3 website ) into here, then untar it.

cd description.1
cp /path/to/tarfile/Grid_dpww1_0.6_dist.tar.gz .
gunzip Grid_dpww1_0.6_dist.tar.gz
tar xvf Grid_dpww1_0.6_dist.tar

Now move the second supplied tarfile into here, then untar it also.

cp /path/to/tarfile/design_demo3_point1.tar.gz .
gunzip design_demo3.tar.gz
tar xvf design_demo3.tar

Note that there is a replacement .mapbc file in the second tar file to override the one supplied on the DPW site. The only difference is the boundary condition on the symmetry plane, which for our purposes here, should be set to 3080 (sliding tangency).

If you examine the supplied rubber.data file, you will see two functions defined. One is the explicit lift constraint with a lower bound of 0.50, and the other is the objective function, based on the drag coefficient. Note that a weighting parameter has been used on both to scale the typical values of the functions to order-1 quantities. I’ve found that this often helps NPSOL move the design along better. Constrained optimization is still very much an art though, and I would encourage you to play with settings and see what works on your cases.

You will see that we are using 107 design variables for this case – angle of attack plus a bunch of camber and thickness variables describing the wing shape. The thickness bounds are set such that no thinning of the wing is allowed.

Next head over to the ammo directory. There you will find a template for the ammo.input file which controls the optimization settings. Edit the file and make it look like the following. Set your path to the base directory appropriately, and if your MPI implementation is executed using a command other than ‘mpirun’ (such as ‘mpiexec’), then include it as needed. Also, the current example is set up to run on 256 processors. Feel free to change this as desired, but the value you supply must be consistent with any ‘-np xxx’ MPI option you may have supplied in the command_line.options file above. Note that in the supplied example I have not included any command line options for the mpirun command. I ran this job in a queueing environment which handles all of the MPI runtime options for me. Also note that if your hardware does not have enough memory to run party on this larger grid (mine happened to have enough, 4 GB), you will have to specify the use of pparty below instead.

Number of processors to use
256
Optimization package
5
Base directory from which to run optimization
'/misc/work12/nielsen/Demo3'
Number of design points
1
Weights for each design point
1.0
Grid type for each design point
2
Operation to perform
3
Restart the optimization
0
MASSOUD (=1) or Bandaid (=2) DV's
1
Diagnostics flag
0
Maximum number of lo-fi functions per subproblem
30
Maximum number of lo-fi subproblem iterations
20
Relative convergence criterion for subproblem
1.e-5
Absolute feasibility tolerance for constraint violation
0.01
Number of Cp slices followed by pairs of boundary indices for slices
0
Boundary pairs for Cp slices
Number of bodies with spatial transforms
1
List of bodies with spatial transforms
1
Body grouping desired (0=no, 1=yes)
0
Use pparty instead of party (0=no, 1=yes)
0
Executable for running MPI programs
'mpirun'

Perform a lift-constrained drag minimization using the design driver

As before, enter the following command:

./opt_driver --sleep_delay 30 > screen.output &

This will fire up the design driver, and the design process will start up. You can monitor the progress by watching the screen.output file.

When the run finishes (about 12 hours or so, depending on your hardware – the optimizer will call the flow and adjoint solvers about 40 times each…designs with explicit constraints tend to be very costly), you should get a npsol.printfile and a npsol.summaryfile in your top-level directory. Examining the output, you should see that we didn’t quite give NPSOL enough iterations to fully converge the problem. Feel free to do it with more, or restart it from the current solution. But this serves our purposes for now. You should see that the objective function has decreased from 5.45 to roughly 4.64, while the constraint has not quite been satisfied – the lift should currently be sitting at about 0.493. (The documentation for NPSOL says that constraints are only guaranteed to be satisfied at convergence.) Nevertheless, the drag has been reduced roughly 18 counts, from 0.0233 to 0.0215. Plotting up the ../model.1/Flow/forces.tec file (simple file that contains lift, drag, L/D history during the design) reveals the following history for the lift and drag coefficients.

You can see that NPSOL tends to jump around a lot during the design procedure.