The following is an aerodynamic optimization case for the MD 30N30P multi-element Airfoil

```Case: Multi-element Airfoil
Geometry: MD 30N30P
Objective function: Lift coefficient
Design variables:
20 FFD points for the main element shape
Pitch variables for the slat and flap
Translation variables for the slat and flap
Angle of attack
27 in total
Constraints: Drag coefficient
Mach number: 0.2
Reynolds number: 4.5 million
Mesh cells: ~13,569
Solver: DARhoSimpleFoam
``` Fig. 1. Mesh and FFD points for the 30N30P multi-element airfoil

In this tutorial, we set up three FFD blocks (see Fig.1) that cover the slat (vol=0), main airfoil (vol=1), and flap (vol=2). Check the genFFD.py file in the FFD folder. We use the snappyHexMesh utility in OpenFOAM to generate the mesh.

In terms of the design variables setup, we use 20 FFD points to change the shape of the main airfoil element. Then, we use the following functions to rotate and translate the slat and flap:

```def twistslat(val, geo):
for i in range(2):
geo.rot_z["slatAxis"].coef[i] = -val

def translateslat(val, geo):
C = geo.extractCoef("slatAxis")
dx = val
dy = val
for i in range(len(C)):
C[i, 0] = C[i, 0] + dx
for i in range(len(C)):
C[i, 1] = C[i, 1] + dy
geo.restoreCoef(C, "slatAxis")

def twistflap(val, geo):
for i in range(2):
geo.rot_z["flapAxis"].coef[i] = -val

def translateflap(val, geo):
C = geo.extractCoef("flapAxis")
dx = val
dy = val
for i in range(len(C)):
C[i, 0] = C[i, 0] + dx
for i in range(len(C)):
C[i, 1] = C[i, 1] + dy
geo.restoreCoef(C, "flapAxis")
```

The rotation and translation are achieved by rotating the reference axis, e.g., geo.rot_z[“slatAxis”].coef[i], or translating the coordinates of the reference axis, e.g., C[i, 0] = C[i, 0] + dx.

To use the above functions, we need to first define the reference axis for slat and flap. The reference axis for the slat is defined near its trailing edge while the reference axis for the flap is define near its leading edge.

```# Slat refAxis
xSlat = [-0.027, -0.027]
ySlat = [-0.109, -0.109]
zSlat = [0.0, 0.1]
cSlat = pySpline.Curve(x=xSlat, y=ySlat, z=zSlat, k=2)
# Flap refAxis
xFlap = [0.875, 0.875]
yFlap = [0.014, 0.014]
zFlap = [0.0, 0.1]
cFlap = pySpline.Curve(x=xFlap, y=yFlap, z=zFlap, k=2)
```

For the objective function, we want to maximize the lift while keeping the drag constant.

```# Add objective
```

To run this case, first download tutorials and untar it. Then go to tutorials-main/30N30P_MultiElement_Airfoil and run the “preProcessing.sh” script to generate the mesh:

```./preProcessing.sh
```

NOTE: the above command will just download the mesh. If you want to re-generate the mesh or change the mesh density, run `preProcessing_reGenMesh.sh` instead (the mesh generation process make take up to an hour). Then, use the following command to run the optimization with 4 CPU cores:

```mpirun -np 4 python runScript.py 2>&1 | tee logOpt.txt
```

The case ran for 43 iterations. The initial lift coefficient is 3.416 and the optimized lift coefficient is 3.509 with an increase of 2.7%.

NOTE: By default, this case uses the Jacobian free option in daOptions: “adjJacobianOption”: “JacobianFree”. This means that you need to compile the AD version of OpenFOAM and DAFoam (see here). If you use the Docker image, they have been compiled so no additional action is needed. If you haven’t compiled the AD version, set this: “adjJacobianOption”: “JacobianFD”. Fig. 2. Evolution of airfoil shape and velocity distribution