4 DAFoam : Discrete Adjoint with OpenFOAM
8 Common functions for DAFoam optimization setup.
21 from petsc4py
import PETSc
23 warnings.filterwarnings(
"once")
24 np.set_printoptions(precision=16, suppress=
True)
29 Update the design surface and run the primal solver to get objective function values.
33 Info(
"+--------------------------------------------------------------------------+")
34 Info(
"| Evaluating Objective Functions %03d |" % DASolver.nSolvePrimals)
35 Info(
"+--------------------------------------------------------------------------+")
36 Info(
"Design Variables: ")
45 DVGeo.setDesignVars(xDV)
46 DASolver.setDesignVars(xDV)
49 DVCon.evalFunctions(funcs)
55 DASolver.evalFunctions(funcs, evalFuncs=evalFuncs)
60 Info(
"Objective Functions: ")
62 Info(
"Flow Runtime: %g" % (b - a))
71 Update the design surface and run the primal solver to get objective function values.
72 This is the multipoint version of calcObjFuncValues
76 Info(
"+--------------------------------------------------------------------------+")
77 Info(
"| Evaluating Objective Functions %03d |" % DASolver.nSolvePrimals)
78 Info(
"+--------------------------------------------------------------------------+")
79 Info(
"Design Variables: ")
90 DVGeo.setDesignVars(xDV)
91 DASolver.setDesignVars(xDV)
93 nMultiPoints = DASolver.getOption(
"nMultiPoints")
95 for i
in range(nMultiPoints):
97 Info(
"--Solving Primal for Configuration %d--" % i)
102 DVCon.evalFunctions(funcs)
107 setMultiPointCondition(xDV, i)
113 DASolver.evalFunctions(funcs, evalFuncs=evalFuncs)
116 DASolver.saveMultiPointField(i)
119 if funcs[
"fail"]
is True:
122 if DASolver.getOption(
"debug"):
123 Info(
"Objective Functions for Configuration %d: " % i)
127 setMultiPointObjFuncs(funcs, funcsMP, i)
129 funcsMP[
"fail"] = fail
131 Info(
"Objective Functions MultiPoint: ")
135 Info(
"Flow Runtime: %g" % (b - a))
142 Update the design surface and run the primal solver to get objective function values.
143 This is the unsteady adjoint version of calcObjFuncValues
147 Info(
"+--------------------------------------------------------------------------+")
148 Info(
"| Evaluating Objective Functions %03d |" % DASolver.nSolvePrimals)
149 Info(
"+--------------------------------------------------------------------------+")
150 Info(
"Design Variables: ")
159 DVGeo.setDesignVars(xDV)
160 DASolver.setDesignVars(xDV)
163 DVCon.evalFunctions(funcs)
170 setObjFuncsUnsteady(DASolver, funcs, evalFuncs)
173 DASolver.setTimeInstanceVar(mode=
"list2Mat")
178 Info(
"Objective Functions: ")
180 Info(
"Flow Runtime: %g" % (b - a))
189 Run the adjoint solver and get objective function sensitivities.
193 Info(
"+--------------------------------------------------------------------------+")
194 Info(
"| Evaluating Objective Function Sensitivities %03d |" % DASolver.nSolveAdjoints)
195 Info(
"+--------------------------------------------------------------------------+")
200 DASolver.writeDesignVariable(
"designVariableHist.txt", xDV)
203 DASolver.writeDeformedFFDs()
209 DVCon.evalFunctionsSens(funcsSens)
212 DASolver.solveAdjoint()
215 DASolver.evalFunctionsSens(funcsSens, evalFuncs=evalFuncs)
220 with np.printoptions(precision=16, threshold=5, suppress=
True):
221 Info(
"Objective Function Sensitivity: ")
223 Info(
"Adjoint Runtime: %g s" % (b - a))
226 DASolver.writeTotalDeriv(
"totalDerivHist.txt", funcsSens, evalFuncs)
228 fail = funcsSens[
"fail"]
230 return funcsSens, fail
235 Run the adjoint solver and get objective function sensitivities.
236 This is the multipoint version of calcObjFuncSens
240 Info(
"+--------------------------------------------------------------------------+")
241 Info(
"| Evaluating Objective Function Sensitivities %03d |" % DASolver.nSolveAdjoints)
242 Info(
"+--------------------------------------------------------------------------+")
249 DASolver.writeDesignVariable(
"designVariableHist.txt", xDV)
252 DASolver.writeDeformedFFDs()
257 nMultiPoints = DASolver.getOption(
"nMultiPoints")
259 for i
in range(nMultiPoints):
261 Info(
"--Solving Adjoint for Configuration %d--" % i)
266 DVCon.evalFunctionsSens(funcsSens)
269 DASolver.setMultiPointField(i)
274 setMultiPointCondition(xDV, i)
277 DASolver.solveAdjoint()
280 DASolver.evalFunctionsSens(funcsSens, evalFuncs=evalFuncs)
282 if funcsSens[
"fail"]
is True:
285 if DASolver.getOption(
"debug"):
286 with np.printoptions(precision=16, threshold=5, suppress=
True):
287 Info(
"Objective Function Sensitivity: ")
291 setMultiPointObjFuncsSens(xDV, funcs, funcsSens, funcsSensMP, i)
293 funcsSensMP[
"fail"] = fail
296 with np.printoptions(precision=16, threshold=5, suppress=
True):
297 Info(
"Objective Function Sensitivity MultiPoiint: ")
301 Info(
"Adjoint Runtime: %g s" % (b - a))
303 return funcsSensMP, fail
308 Run the adjoint solver and get objective function sensitivities.
309 This is the unsteady adjoint version of calcObjFuncSens
313 Info(
"+--------------------------------------------------------------------------+")
314 Info(
"| Evaluating Objective Function Sensitivities %03d |" % DASolver.nSolveAdjoints)
315 Info(
"+--------------------------------------------------------------------------+")
322 DASolver.writeDesignVariable(
"designVariableHist.txt", xDV)
325 DASolver.writeDeformedFFDs()
328 DASolver.setTimeInstanceVar(mode=
"mat2List")
331 funcsSensCombined = {}
333 funcsSensAllInstances = []
335 mode = DASolver.getOption(
"unsteadyAdjoint")[
"mode"]
336 nTimeInstances = DASolver.getOption(
"unsteadyAdjoint")[
"nTimeInstances"]
337 if mode ==
"hybridAdjoint":
339 elif mode ==
"timeAccurateAdjoint":
347 DASolver.calcPrimalResidualStatistics(
"calc")
350 DASolver.zeroTimeAccurateAdjointVectors()
352 for i
in range(nTimeInstances - 1, iEnd, -1):
354 Info(
"--Solving Adjoint for Time Instance %d--" % i)
359 DVCon.evalFunctionsSens(funcsSens)
362 DASolver.setTimeInstanceField(i)
365 DASolver.solveAdjoint()
368 DASolver.evalFunctionsSens(funcsSens, evalFuncs=evalFuncs)
370 if funcsSens[
"fail"]
is True:
373 if DASolver.getOption(
"debug"):
374 with np.printoptions(precision=16, threshold=5, suppress=
True):
375 Info(
"Objective Function Sensitivity: ")
378 funcsSensAllInstances.append(funcsSens)
380 setObjFuncsSensUnsteady(DASolver, funcs, funcsSensAllInstances, funcsSensCombined)
382 funcsSensCombined[
"fail"] = fail
385 with np.printoptions(precision=16, threshold=5, suppress=
True):
386 Info(
"Objective Function Sensitivity Unsteady Adjoint: ")
387 Info(funcsSensCombined)
390 Info(
"Adjoint Runtime: %g s" % (b - a))
392 return funcsSensCombined, fail
400 xDV = DVGeo.getValues()
402 funcs, fail = objFun(xDV)
407 def runAdjoint(objFun=calcObjFuncValues, sensFun=calcObjFuncSens, fileName=None):
409 Just run the primal and adjoint
412 DASolver.runColoring()
413 xDV = DVGeo.getValues()
415 funcs, fail = objFun(xDV)
417 funcsSens, fail = sensFun(xDV, funcs)
420 if fileName
is not None:
422 fOut = open(fileName,
"w")
423 for funcName
in evalFuncs:
425 fOut.write(funcName +
" " + shapeVar +
"\n")
427 nDVs = len(funcsSens[funcName][shapeVar])
430 for n
in range(nDVs):
431 line = str(funcsSens[funcName][shapeVar][n]) +
"\n"
436 return funcsSens, fail
441 Run the forward mode AD for the primal solver to compute the brute force total
442 derivative. This is primarily used in verification of the adjoint accuracy
445 if not DASolver.getOption(
"useAD")[
"mode"] ==
"forward":
446 Info(
"runForwardAD only supports useAD->mode=forward!")
447 Info(
"Please set useAD->mode to forward and rerun!")
449 DASolver.setOption(
"useAD", {
"dvName": dvName,
"seedIndex": seedIndex})
450 DASolver.updateDAOption()
454 def solveCL(CL_star, alphaName, liftName, objFun=calcObjFuncValues, eps=1e-2, tol=1e-4, maxit=10):
456 Adjust the angle of attack or pitch to match the target lift.
457 This is usually needed for wing aerodynamic optimization
461 Info(
"+--------------------------------------------------------------------------+")
462 Info(
"| Running SolveCL to find alpha that matches target CL |")
463 Info(
"+--------------------------------------------------------------------------+")
464 Info(
"eps: %g tol: %g maxit: %g" % (eps, tol, maxit))
466 xDVs = DVGeo.getValues()
467 alpha = xDVs[alphaName]
469 for i
in range(maxit):
471 xDVs[alphaName] = alpha
473 funcs, fail = objFun(xDVs)
474 CL0 = funcs[liftName]
475 Info(
"alpha: %f, CL: %f" % (alpha.real, CL0))
476 if abs(CL0 - CL_star) / CL_star < tol:
477 Info(
"Completed! alpha = %f" % alpha.real)
480 alphaVal = alpha + eps
481 xDVs[alphaName] = alphaVal
483 funcsP, fail = objFun(xDVs)
484 CLP = funcsP[liftName]
485 deltaAlpha = (CL_star - CL0) * eps / (CLP - CL0)
493 Compute finite-difference sensitivity
496 xDV = DVGeo.getValues()
499 deltaX = DASolver.getOption(
"adjPartDerivFDStep")[
"FFD"]
502 for funcName
in evalFuncs:
503 gradFD[funcName] = {}
505 gradFD[funcName][shapeVar] = np.zeros(len(xDV[shapeVar]))
507 print(
"-------FD----------", deltaX, flush=
True)
511 nDVs = len(xDV[shapeVar])
514 for i
in range(nDVs):
517 xDV[shapeVar][i] += deltaX
518 funcp, fail = objFun(xDV)
519 xDV[shapeVar][i] -= 2.0 * deltaX
520 funcm, fail = objFun(xDV)
521 xDV[shapeVar][i] += deltaX
522 for funcName
in evalFuncs:
523 gradFD[funcName][shapeVar][i] = (funcp[funcName] - funcm[funcName]) / (2.0 * deltaX)
526 if fileName
is not None:
528 fOut = open(fileName,
"w")
529 fOut.write(
"DeltaX: " + str(deltaX) +
"\n")
530 for funcName
in evalFuncs:
532 fOut.write(funcName +
" " + shapeVar +
"\n")
534 nDVs = len(gradFD[funcName][shapeVar])
537 for n
in range(nDVs):
538 line = str(gradFD[funcName][shapeVar][n]) +
"\n"
546 if DASolver.getOption(
"runLowOrderPrimal4PC")[
"active"]:
547 DASolver.setOption(
"runLowOrderPrimal4PC", {
"isPC":
True})
548 DASolver.updateDAOption()
550 DASolver.dRdWTPC = PETSc.Mat().create(PETSc.COMM_WORLD)
551 DASolver.solver.calcdRdWT(DASolver.xvVec, DASolver.wVec, 1, DASolver.dRdWTPC)
552 DASolver.setOption(
"runLowOrderPrimal4PC", {
"isPC":
False})
553 DASolver.updateDAOption()
558 Print information and flush to screen for parallel cases
563 print(message, flush=
True)