Multipoint Optimization

Introduction

Optimization does not have to be limited to a single flight condition. This section goes through the same optimization as the single point case, except with one more flight condition. Instead of rewriting the code from scratch, the differences in code will be pointed out.

Files

Copy the FFD file, ffd.xyz, and the CGNS mesh file, n0012.cgns, generated previously, into the directory.

Create the following empty runscript in the current directory:

  • airfoil_multiopt.py

Highlighting the changes required in the multipoint optimization script

Open the file airfoil_multiopt.py in your favorite text editor. Copy the script from airfoil_opt.py and change the following sections for multipoint optimization.

Specifying parameters for the optimization

For multipoint optimization, the parameters have to be specified in lists of the same size.

# specify flight conditions and constraints
mach = [0.4, 0.5]
alt = [10000, 10000]
alpha = [1, 1]
mycl = [0.5, 0.5]
# number of points in multipoint optimization
nFlowCases = len(mach)
# assign number of processors
nGroup = 1
nProcPerGroup = MPI.COMM_WORLD.size

Set the AeroProblem

For more than one AeroProblem, a list needs to be created. Each AeroProblem is created with the respective optimization point and appended to the list.

aeroProblems = []
for i in range(nFlowCases):
    ap = AeroProblem(
        name="fc%d" % i,
        alpha=alpha[i],
        mach=mach[i],
        altitude=alt[i],
        areaRef=1.0,
        chordRef=1.0,
        evalFuncs=["cl", "cd"],
    )
    # Add angle of attack variable
    ap.addDV("alpha", value=alpha[i], lower=0, upper=10.0, scale=1.0)
    aeroProblems.append(ap)

Optimization callback functions

The same for-loop needs to be added to the callback functions. The lines that require a call to the an AeroProblem is now put into a for-loop to iterate through all of them.

def cruiseFuncs(x):
    if MPI.COMM_WORLD.rank == 0:
        print(x)
    # Set design vars
    DVGeo.setDesignVars(x)
    # Evaluate functions
    funcs = {}
    DVCon.evalFunctions(funcs)

    for i in range(nFlowCases):
        if i % nGroup == ptID:
            aeroProblems[i].setDesignVars(x)
            CFDSolver(aeroProblems[i])
            CFDSolver.evalFunctions(aeroProblems[i], funcs)
            CFDSolver.checkSolutionFailure(aeroProblems[i], funcs)
    if MPI.COMM_WORLD.rank == 0:
        print(funcs)
    return funcs


def cruiseFuncsSens(x, funcs):
    funcsSens = {}
    DVCon.evalFunctionsSens(funcsSens)
    for i in range(nFlowCases):
        if i % nGroup == ptID:
            CFDSolver.evalFunctionsSens(aeroProblems[i], funcsSens)
            CFDSolver.checkAdjointFailure(aeroProblems[i], funcsSens)
    if MPI.COMM_WORLD.rank == 0:
        print(funcsSens)
    return funcsSens


def objCon(funcs, printOK):
    # Assemble the objective and any additional constraints:
    funcs["obj"] = 0.0
    for i in range(nFlowCases):
        ap = aeroProblems[i]
        funcs["obj"] += funcs[ap["cd"]] / nFlowCases
        funcs["cl_con_" + ap.name] = funcs[ap["cl"]] - mycl[i]
    if printOK:
        print("funcs in obj:", funcs)
    return funcs


In the objCon function, the $c_L$ constraint is also placed into the for-loop.

Optimization problem

Adding the constraints to the optimization problem requires adding them to each AeroProblem.

# Create optimization problem
optProb = Optimization("opt", MP.obj, comm=MPI.COMM_WORLD)

# Add objective
optProb.addObj("obj", scale=1e4)

# Add variables from the AeroProblem
ap.addVariablesPyOpt(optProb)

# Add DVGeo variables
DVGeo.addVariablesPyOpt(optProb)

# Add constraints
DVCon.addConstraintsPyOpt(optProb)
for i in range(nFlowCases):
    ap = aeroProblems[i]
    optProb.addCon("cl_con_" + ap.name, lower=0.0, upper=0.0, scale=1.0)

# The MP object needs the 'obj' and 'sens' function for each proc set,
# the optimization problem and what the objcon function is:
MP.setProcSetObjFunc("cruise", cruiseFuncs)
MP.setProcSetSensFunc("cruise", cruiseFuncsSens)
MP.setObjCon(objCon)
MP.setOptProb(optProb)
optProb.printSparsity()

Run it yourself!

The script can be run in the same way:

$ mkdir output
$ mpirun -np 4 python airfoil_multiopt.py | tee output.txt