Bangalore 05

Embed Size (px)

Citation preview

  • 7/30/2019 Bangalore 05

    1/9

    Post SAROD Workshop-2005

    Using Automatic Differentiation

    for Adjoint CFD Code Development

    M.B. Giles

    D. Ghate

    M.C. Duta

    Abstract

    This paper addresses the concerns of CFD code developers who are facing the task of creating adiscrete adjoint CFD code for design optimisation. It discusses how the development of such acode can be greatly eased through the selective use of Automatic Differentiation, and how eachstage of the software development process can be subjected to a sequence of checks to ensure thecorrectness of the final software.

    Key Words: Discrete adjoint, design optimisation, automatic differentiation

    1 Introduction

    The use of adjoint methods for design optimisationhas been a major research area in the last few years.Pironneau first introduced the idea of using an adjointapproach in fluid dynamic context [18] but the appli-cation to aeronautical design optimisation has beenpioneered by Jameson [14, 15, 19].

    Jameson uses the continuous adjoint approach inwhich the adjoint equation is formulated at the differ-ential equation level, and it is then discretised. In

    contrast to this, Elliott and Peraire [5] and others[1, 9] follow a discrete adjoint approach in which onestarts with nonlinear discrete equations, and then for-mulates the corresponding discrete adjoint equations.

    There is no fundamental reason to prefer one ap-proach over the other. Proponents of the discrete ap-proach sometimes point to the fact that the contin-uous approach yields a design gradient (the gradientof the objective function with respect to the designvariables) which is not quite consistent with the dis-crete objective function being optimised. However, itis as good an approximation to the true design gra-dient as the discrete gradient, and provided one uses

    an optimisation strategy (e.g. preconditioned steepestdescent) which simply drives the continuous gradientto zero, then it will yield results as good as the discreteapproach.

    Oxford University Computing Laboratory, Oxford, U.K.

    cMike Giles, Devendra Ghate & Mihai DutaSAROD-2005Published in 2005 by Tata McGraw-Hill

    Our strong preference for the discrete approach ispragmatic in nature, and based on the following keypoints:

    There is a clear prescriptive process for constructingthe discrete adjoint equations and boundary condi-tions;

    In most cases, if an adjoint iterative solution tech-nique is used then it is guaranteed to give an iter-ative convergence rate equal to that of the originalnonlinear code;

    Automatic Differentiation can be used to substan-tially ease the development of the adjoint CFD code.

    The purpose of this paper is to explain these threepoints, with particular emphasis on the final point.One of the earliest applications which motivated thedevelopment of reverse mode AD (which can standfor either Algorithmic Differentiation [11] or Auto-matic Differentiation [12]) was in fluid dynamics, anadjoint version of an ocean circulation model beingdeveloped at MIT [6]. In the aeronautical context,perhaps the first application was by Mohammadi [16].In simple, small applications, it is sometimes possibleto use AD as a black-box, feeding in a nonlinearcode and obtaining a corresponding linear perturba-tion (forward mode AD) or adjoint (reverse mode AD)code. However, in real applications with very largecodes in which one wants to minimise the CPU andmemory requirements, it is usually necessary to applythe AD very selectively. This is particularly the casein design optimisation in which one is using a fixedpoint iteration to solve the original nonlinear equa-tions [7, 8].

  • 7/30/2019 Bangalore 05

    2/9

    2 M.B. Giles, D. Ghate and M.C. Duta

    2 Mathematical overview

    2.1 Linear and adjoint sensitivitypropagation

    Suppose we have a design process in which a set of de-sign parameters , leads to a computational grid withcoordinates X, producing a discrete flow solution U,and hence a scalar output J which is to be optimised:

    X U J.

    In order to use a gradient-based optimisation method,one wishes to compute the derivative ofJ with respectto . Adopting the notation used in the AD commu-nity, let , X, U , J denote the derivative with respectto one particular component of (or more generallyin one particular direction in the design space).

    If at each stage in the process the output is an ex-plicit function of the input, then straightforward dif-ferentiation gives

    X =X

    , U =

    U

    XX, J =

    J

    UU,

    and hence

    J =J

    U

    U

    X

    X

    ,

    Again following the notation used in the AD com-munity the adjoint quantities , X , U , J denote thederivatives of J with respect to ,X,U,J, respec-tively, with J = 1 by definition. Differentiating again,

    (and with a superscriptT

    denoting a matrix or vectortranspose) one obtains

    def

    =

    J

    T=

    J

    X

    X

    T=

    X

    TX,

    and similarly

    X =

    U

    X

    TU , U =

    U

    J

    TJ,

    giving

    =X

    T U

    XTU

    JT

    J.

    Note that whereas the linear sensitivity analysisproceeds forwards through the process (forward modein AD terminology)

    X U J ,

    the adjoint analysis proceeds backwards (reverse modein AD terminology),

    X U J.

    Given these definitions, the sensitivity of the outputJ to the inputs can be evaluated in a number ofways,

    J = UT

    U = XT

    X = T,

    so it is possible to proceed forwards through part ofthe process and combine this with going backwardsthrough the other part of the process. This is use-ful in applications in which part of the process is ablack-box which cannot be touched. For example, ifthe step X involves a proprietary CAD systemor grid generator, then the only option may be to ap-proximate the forward mode linear sensitivity througha central finite difference using X().

    The advantage of using the adjoint approach as faras possible is that its computational cost is indepen-dent of the number of design variables, whereas the

    cost of the forward linear sensitivity analysis increaseslinearly with the number of design variables.

    2.2 Fixed point iteration

    2.2.1 Nonlinear and linear equations

    In CFD applications, the flow solution U is not anexplicit function of the grid coordinates X, but insteadis defined implicitly through the solution of a set ofnonlinear discrete flow equations of the form

    N(U, X) = 0. (1)

    To solve these equations, many CFD algorithms use

    iterative methods which can be written as

    Un+1 = Un P(Un, X) N(Un, X), (2)

    where P is a non-singular square matrix which is adifferentiable function of its arguments. If P were de-fined to be L1 where

    L =N

    U,

    is the non-singular Jacobian matrix, this would be theNewton-Raphson method which converges quadrati-cally. However, in the iterative methods used in CFD,

    P is a poor approximation to L

    1

    and therefore giveslinear convergence asymptotically, with the final rateof convergence being given by the magnitude of thelargest eigenvalue of the matrix I P(U, X) L(U, X),where I is the identity matrix.

    Differentiating Equation (1) gives

    L U + N = 0, (3)

    where N is defined as

    N =N

    XX,

  • 7/30/2019 Bangalore 05

    3/9

    Using Automatic Differentiation for Adjoint CFD Code Development 3

    with both derivatives being evaluated based on theimplicitly-defined baseline solution U(X).

    Similarly, differentiating Equation (2) around afully-converged baseline solution in which Un = Ugives

    Un+1 = Un P

    L Un + N

    , (4)

    with P based on U(X). This will converge to the so-lution of Equation (3) with exactly the same terminalrate of convergence as the nonlinear iteration.

    To be more specific, the simple predictor/correctortime-marching used in the model application to bediscussed later has the linearisation

    U = Un T

    L Un + N

    ,

    U

    n+1

    =

    U

    n

    T

    L

    U

    +

    N

    ,

    where T is a diagonal matrix containing thearea/timestep values for each cell. This can be ex-pressed in the form of Equation (4) with

    P = T (I LT).

    2.2.2 Adjoint equations

    SinceU = L1N ,

    the adjoint sensitivities satisfy the equation

    N = (LT)1U ,

    which implies that

    LTN + U = 0.

    This equation can be solved iteratively using the ad-joint iteration

    Nn+1

    = Nn PT

    LT N

    n+ U

    . (5)

    Note the use of the transposed preconditioner PT. Inthe case of the predictor/corrector time-marching,

    PT = (I T LT) T = T (I LTT).

    Thus the adjoint iteration can be implemented usingexactly the same predictor/corrector time-marching.

    The adjoint iteration converges at exactly the samerate as the linear iteration, since IPTLT has thesame eigenvalues as IP L. Furthermore, if the linearand adjoint iterations both start from zero initial con-

    ditions (U0 = N0

    = 0) then they give identical values

    for the overall objective function gradient after equalnumbers of iterations since

    (Nn

    )TN = UT

    Un. (6)

    This equivalence is a consequence of the following tworesults which can be proved inductively:

    Un = n1m=0

    (I P L)m PN

    Nn

    = n1m=0

    I PTLT

    mPT U

    2.2.3 Other iterative solvers

    Not all iterative schemes of the form given by Equa-

    tions (2) and (4) are naturally self-adjoint, in the sensethat the adjoint iteration is essentially the same as thelinear iteration. Reference [7] constructs the adjointiteration for multi-step Runge-Kutta methods with apartial update of viscous terms (a popular method in-troduced by Jameson) and also discusses the use ofmultigrid for which the adjoint restriction operatorhas to be the transpose of the original prolongationoperator, and vice versa.

    There are also some iterative solution methodswhich are not of the form given by Equations (2) and(4), for example the use of GMRES to solve Equations(1) and (3). In these cases, the iterative solution of the

    discrete adjoint equations can probably still be solvedwith the same final convergence rate, but the proof ofthis will depend on the fact that L and LT have thesame eigenvalues. If a preconditioner P is used to ac-celerate the convergence of the linear solver, then PT

    should be used as the preconditioner for the adjointsolver, since again P L and PTLT have the same eigen-values. However, the feature of equivalence betweenthe linear and adjoint solutions after equal numbersof iterations is unlikely to exist for these methods.

    2.3 More general outputs

    A final comment is that most objective functions of

    interest depend on X as well as U. In the forwardlinear analysis, the only modification this introducesis to the final calculation,

    J =J

    UU +

    J

    XX,

    while in the reverse adjoint calculation the equationfor X is

    X =

    N

    X

    TN +

    J

    X

    T.

  • 7/30/2019 Bangalore 05

    4/9

    4 M.B. Giles, D. Ghate and M.C. Duta

    3 Automatic Differentiation

    The previous section outlined the mathematics of thediscrete adjoint approach, and tried to substantiate

    the first two of the key points presented in the Intro-duction, that there is a clear prescriptive process toconstructing the discrete adjoint equations and solu-tion procedure, and in most cases it is guaranteed toconverge at exactly the same rate as the terminal con-vergence of the original nonlinear solver. This meansthat the adjoint solver benefits immediately from allof the research and hard work that has gone into therapid solution of the nonlinear discrete flow equations.

    This section now addresses the third point, how theprocess of creating the adjoint program can be sim-plified through the use of Automatic Differentiation.To do this, we begin by looking at the mathematics

    of adjoint sensitivity calculation at the lowest possi-ble level to understand how automatic differentiationworks.

    Consider a computer program which starts with anumber of input variables ui, i = 1, . . . I which can berepresented collectively as an input vector u0. Eachstep in the execution of the computer program com-putes a new value as a function of two previous val-ues; unitary functions such as exp(x) can be viewed asa binary function with no dependence on the secondparameter. Appending this new value to the vectorof active variables, the nth execution step can be ex-pressed as

    un = fn(un1)

    un1

    fn(un1)

    , (7)

    where fn is a scalar function of two of the elementsof un1. The result of the complete N steps of thecomputer program can then be expressed as the com-position of these individual functions to give

    uN = fN fN1 . . . f2 f1(u0). (8)

    Defining un to be the derivative of the vector un

    with respect to one particular element of u0

    , differen-tiating (7) gives

    un = Ln un1, Ln =

    In1

    fn/un1

    , (9)

    with In1 being the identity matrix with dimensionequal to the length of the vector un1. The derivativeof (8) then gives

    uN = LN LN1 . . . L2 L1 u0, (10)

    which gives the sensitivity of the entire output vectorto the change in one particular element of the inputvector. The elements of the initial vector u0 are allzero except for a unit value for the particular element

    of interest. If one is interested in the sensitivity to NIdifferent input elements, then (10) must be evaluatedfor each one, at a cost which is proportional to NI.

    The above description is of the forward mode of ADsensitivity calculation, which is intuitively quite natu-ral. The reverse, or adjoint, mode is computationallymuch more efficient when one is interested in the sen-sitivity of a small number of output quantities withrespect to a large number of input parameters. Defin-ing the column vector un to be the derivative of aparticular element of the output vector uN

    iwith re-

    spect to the elements of un, then through the chainrule of differentiation we obtain

    un1

    T=

    uNi

    un1=

    uNi

    unun

    un1=

    unT

    Ln,

    = un1 =

    LnT

    un. (11)

    Hence, the sensitivity of the particular output elementto all of the elements of the input vector is given by

    u0 =

    L1T

    L2T

    . . .

    LN1T

    LNT

    uN. (12)

    Note that the reverse mode calculation proceeds back-wards from n = N to n = 1. Therefore, it is necessaryto first perform the original calculation forwards from

    n = 1 to n = N, storing all of the partial derivativesneeded for Ln, before then doing the reverse modecalculation.

    If one is interested in the sensitivity of NO differentoutput elements, then (12) must be evaluated for eachone, at a cost which is proportional to NO. Thus thereverse mode is computationally much more efficientthan the forward mode when NO NI.

    Looking in more detail at what is involved in (9)and (11), suppose that the nth step of the originalprogram involves the computation

    c = f(a, b).

    The corresponding forward mode step will be

    c =f

    aa +

    f

    bb

    at a computational cost which is no more than a fac-tor 3 greater than the original nonlinear calculation.Looking at the structure of (Ln)T, one finds that thecorresponding reverse mode step consists of two cal-culations:

    a = a +f

    ac

  • 7/30/2019 Bangalore 05

    5/9

    Using Automatic Differentiation for Adjoint CFD Code Development 5

    b = b +f

    bc.

    At worst, this has a cost which is a factor 4 greater

    than the original nonlinear calculation.The above description outlines a clear algorithmic

    approach to the reverse mode calculation of sensitivityinformation. However, the programming implemen-tation can be tedious and error-prone. Fortunately,tools have been developed to automate this process,either through operator overloading involving a pro-cess known as taping which records all of the par-tial derivatives in the nonlinear calculation then per-forms the reverse mode calculations [12], or throughsource code transformation which takes as an inputthe original program and generates a new program toperform the necessary calculations [6]. Further infor-

    mation about AD tools and publications is availablefrom the AD community website www.autodiff.orgwhich includes links to all of the major groups workingin this field.

    In the present work, we are using Tapenade, devel-oped by Hascoet and Pascual at INRIA [4, 13]. Thesoftware is written in Java, and it applies source trans-formation to codes written in FORTRAN77; work isin progress to extend the software to C and C++ butthere are technical difficulties because of their use ofpointers.

    4 Example application

    The example application is a 2D inviscid airfoil codeusing an unstructured grid. The full source code isavailable [10], including the files generated by Tape-nade.

    The nonlinear code uses a cell-centred discretisationtogether with a simple predictor/corrector timemarch-ing, using local timesteps which are also involved inthe definition of a simple first order accurate numer-ical smoothing. The schematic of the nonlinear flowcode is given in Figure 1. There are four key nonlinearroutines which are called from within loops over cellor faces:

    TIME_CELL:computes the local area/timestep for a single cell

    FLUX_FACE:computes the flux through a single regular face

    FLUX_WALL:computes the flux for a single airfoil wall face

    LIFT_WALL:computes the lift contribution from a single airfoilwall face

    Figure 2 shows the schematic of the linear sensitiv-ity flow code. The part of the code before the main

    time-marching loop computes the quantity N; sincethis remains constant throughout the time-marchingit is much more efficient to compute it just oncerather then re-evaluate it at each iteration. The time-

    marching loop then iterates to compute U, and thefinal section then evaluates J. The seven subroutinescalled by the linear flow code are all linearisations ofthe four nonlinear routines, and are generated auto-matically by Tapenade.

    As an example, Figure 3 shows the arguments forthe nonlinear routine FLUX_WALL; the inputs are thecoordinates of the two nodes at either end of the wallface, and the flow variables in the cell next to the face,and the output is an increment to the flux residualfor that same cell. The routines FLUX_WALL_D andFLUX_WALL_DX are the two forward mode linearisa-tions of FLUX_WALL. In the case of FLUX_WALL_D, the

    extra input is qd which represents U in the mathemat-ical formulation, and the extra output is resd which isthe consequential perturbation to res. The suffix Din the function name and the suffix d in the variablenames both stand for dot. FLUX_WALL_DX is similarbut also includes perturbations to each of the coordi-nates. Which variables are considered active, andwhich are treated as being fixed, is controlled by thecommand line arguments supplied to Tapenade whenit creates the new routines.

    The forward mode linearisation is relatively natu-ral, but the reverse mode adjoint code in Figure 4 ismuch less intuitive. The first thing to note is thatthe order in which the different routines is called isthe opposite to the linear code. The first section hasthe calls necessary to compute U, the time-marchingloop iterates to find the value of U, and then the finalsection computes X and then evaluates the product

    J= XT

    X.

    Within the time-marching loop, the reversal of theorder in which the flux and timestep routines arecalled can be explained by noting that L can be viewedas the product of two matrices F A, where A is the ef-fect of the timestep calculation which determines atimestep perturbation in addition to carrying over the

    flow perturbations, and then F is the effect of the lin-earised flux calculation. The adjoint operator is thenLT = (F A)T = ATFT. Thus the fact that the trans-pose of a product of matrices is equal to the product ofthe transposed matrices in the opposite order, leads tothe reversal in the order in which the adjoint routinesare called. A similar behaviour is seen in adjoint vis-cous codes in which a flow gradient is first computedin one loop over edges, and then the viscous flux iscomputed in a second loop over edges [9].

  • 7/30/2019 Bangalore 05

    6/9

    6 M.B. Giles, D. Ghate and M.C. Duta

    define grid and initialise flow field

    begin predictor/corrector time-marching looploop over cells to calculate timestep

    call TIME_CELLloop over regular faces to calculate flux

    call FLUX_FACEloop over airfoil faces to calculate flux

    call FLUX_WALLloop over cells to update solution

    end time-marching loop

    calculate liftloop over boundary faces

    call LIFT_WALL

    Fig.1: Schematic of the nonlinear flow code

    define grid and initialise flow field

    define grid perturbation

    loop over cells -- perturbed timestepcall TIME_CELL_DX

    loop over regular faces -- perturbed fluxcall FLUX_FACE_DX

    loop over airfoil faces -- perturbed fluxcall FLUX_WALL_DX

    begin predictor/corrector time-marching looploop over cells to calculate timestep

    call TIME_CELL_Dloop over regular faces to calculate flux

    call FLUX_FACE_Dloop over airfoil faces to calculate flux

    call FLUX_WALL_Dloop over cells to update solution

    end time-marching loop

    calculate liftloop over boundary faces -- perturbed lift

    call LIFT_WALL_DX

    Fig.2: Schematic of the linear flow code

    FLUX_WALL(x1,x2,q,res)

    FLUX_WALL_D(x1,x2,q,qd,res,resd)

    FLUX_WALL_DX(x1,x1d,x2,x2d,q,qd,res,resd)

    FLUX_WALL_B(x1,x2,q,qb,res,resb)

    FLUX_WALL_BX(x1,x1b,x2,x2b,q,qb,res,resb)

    Fig.3: The arguments of the nonlinear subroutineFLUX WALL and its Tapenade-generated derivatives

    define grid and initialise flow field

    calculate adjoint lift sensitivityloop over boundary faces

    call LIFT_WALL_BX

    begin predictor/corrector time-marching looploop over airfoil faces -- adjoint flux

    call FLUX_WALL_Bloop over regular faces -- adjoint flux

    call FLUX_FACE_Bloop over cells -- adjoint timestep calc

    call TIME_CELL_Bloop over cells to update solution

    end time-marching loop

    loop over airfoil faces -- adjoint fluxcall FLUX_WALL_BX

    loop over regular faces -- adjoint flux

    call FLUX_FACE_BXloop over cells -- adjoint timestep calc

    call TIME_CELL_BX

    loop over nodes to evaluate lift sensitivity

    Fig.4: Schematic of the adjoint flow code

  • 7/30/2019 Bangalore 05

    7/9

    Using Automatic Differentiation for Adjoint CFD Code Development 7

    Looking now in detail at the adjoint versions ofFLUX_WALL in Figure 3, these too operate in reverse.While the linear version FLUX_WALL_D computes

    res = res + K q,for some matrix K, the adjoint version FLUX_WALL_Bcomputes

    q = q + KT res.

    The suffix B in the function name and the suf-fix b in the variable names qb and resb all standfor bar. Thus resb is an unchanged input toFLUX_WALL_B, and qb is incremented appropriately bythe routine. FLUX_WALL_BX is the version which in-cludes variations in the coordinates; this is used toevaluate (N/X)TN as part of the calculation ofX.

    The generation of the linear and adjoint ver-sions of the four nonlinear routines is handled au-tomatically by the Unix Makefile used to createthe executables. For example, when the object fileflux_wall_bx.o is needed for the adjoint executableair_adj, the Makefile runs Tapenade with an ap-propriate set of command line arguments, compilesthe file flux_wall_bx.f which it generates, and thendeletes the FORTRAN source file; in practice itis rarely helpful to look at the Tapenade-generatedsource except to better understand how Tapenadeworks.

    The trickiest part of using Tapenade is correctlyspecifying the status of active variables:

    input only it is never used again after the routineis finished, so its output value is irrelevant;

    output only it is assigned a value within the rou-tine, so its input value is irrelevant;

    input and output in practice the most commoncase, since input variables such as the flow vari-ables will be used again later, and output vari-ables such as the flux residual are in fact incrementsadded to pre-existing values.

    Figure 5 shows the part of the Makefile which usesTapenade to generate the four linear and adjoint rou-tines which are derived from the routine FLUX_WALL

    within the file routines.F. In each case, there is aninitial step which uses the C preprocessor to producepure FORTRAN code. This is processed by Tape-nade to produce the desired output code, which is thencompiled, and finally all unwanted intermediate filesare deleted. The Tapenade flags are fairly obvious;-forward and -reverse specify whether to generatelinear or adjoint code, -vars and -outvars specify theinput and output active variables, and -funcsuffixgives the function suffix to be used in place of the de-fault " d" or " b", depending on the AD mode. Formore information, see the documentation [13].

    flux_wall_d.o: routines.F${GCC} -E -C -P routines.F > routines.f;

    ${TPN} -forward \-head flux_wall \-output flux_wall \-vars "q res" \-outvars "q res" \

    routines.f;${FC} ${FFLAGS} -c flux_wall_d.f;/bin/rm routines.f flux_wall_d.f *.msg

    flux_wall_dx.o: routines.F${GCC} -E -C -P routines.F > routines.f;${TPN} -forward \

    -head flux_wall \-output flux_wall \-vars "x1 x2 q res" \-outvars "x1 x2 q res" \-funcsuffix "_dx" \

    routines.f;${FC} ${FFLAGS} -c flux_wall_dx.f;/bin/rm routines.f flux_wall_dx.f *.msg

    flux_wall_b.o: routines.F${GCC} -E -C -P routines.F > routines.f;${TPN} -backward \

    -head flux_wall \-output flux_wall \-vars "q res" \-outvars "q res" \

    routines.f;${FC} ${FFLAGS} -c flux_wall_b.f;/bin/rm routines.f flux_wall_b.f *.msg

    flux_wall_bx.o: routines.F${GCC} -E -C -P routines.F > routines.f;${TPN} -backward \

    -head flux_wall \-output flux_wall \-vars "x1 x2 q res" \-outvars "x1 x2 q res" \-funcsuffix "_bx" \

    routines.f;${FC} ${FFLAGS} -c flux_wall_bx.f;/bin/rm routines.f flux_wall_bx.f *.msg

    Fig.5: Part of Makefile with Tapenade instructions forgenerating linear and adjoint versions of FLUX WALL;GCC, TPN, FC and FFLAGS correspond to the Gnu Ccompiler, Tapenade, the FORTRAN compiler and itscompilation flags. respectively.

  • 7/30/2019 Bangalore 05

    8/9

    8 M.B. Giles, D. Ghate and M.C. Duta

    5 Validation checks

    Although we have complete confidence in the correct-ness of the linear and adjoint code produced by Tape-

    nade, it is nevertheless good programming practice toimplement validation checks to ensure the software isperforming correctly; in the past, this has helped toidentify cases in which we have incorrectly specifiedthe status of active variables when using Tapenade.This is particularly important in much larger applica-tions than the model one considered in this paper.

    5.1 Individual routines

    One set of checks can be performed at the level ofthe individual routines generated by Tapenade. Inconcept, we have

    a nonlinear routine which computes a vector output

    f(u) given a vector input u;

    a linear routine which computes

    f

    u

    u;

    and an adjoint routine which computes

    f

    u

    Tf.

    By calling the linear and adjoint routines for a se-quence of different unit vectors u and f, each one zeroexcept for a unit value for one element, it is possible toconstruct the matrix f/u which each is effectivelyusing, and check that these are in agreement.

    Checking for consistency against the original non-linear code is possible by using the complex Taylorseries expansion method [20, 2]. If f(u) is assumed tobe a complex analytic function, then a Taylor seriesexpansion gives

    lim0

    I {f(u+iu)}

    =

    f

    uu.

    In this equation, the notation I{. . .} denotes the imag-inary part of a complex quantity. The convergence tothe limiting value is second order in so numericalevaluation with < 108 yields double precision ac-curacy. In practice, we use = 1020. Unlike theusual finite difference approximation of a linear sen-

    sitivity, there is no cancellation effect from the sub-traction of two quantities of similar magnitude, andtherefore no unacceptable loss of accuracy due to ma-chine rounding error. Applying this technique to aFORTRAN code requires little more than replacingall REAL*8 declarations by COMPLEX*16, and definingappropriate complex analytic versions of the intrinsicfunctions min,max,abs.

    The source code [10] includes a test programtestlinadj which performs all of these checks for allfour of the nonlinear routines and their associated lin-ear and adjoint derivatives.

    5.2 Complete codes

    A second set of checks can be applied to the completecodes,

    a nonlinear code which computes J(); a linear code which computes J; and an adjoint code which also computes J.

    The first thing is to check that the linear and ad-joint codes produce the same value for J. Not onlyshould the values agree once both codes have fullyconverged, they should also agree after performingthe same number of iterations if they use an itera-tive solution method of the type described earlier inthe mathematical overview. This is very helpful whendebugging very large codes which may run for a longtime; checking for full agreement down to machine ac-

    curacy after 10 iterations takes much less CPU timethan checking after 10,000 iterations.

    It is usually impractical to apply the complex Taylorseries method to the entire nonlinear code because itrequires too much intervention in the code, so insteadthe final test is to check the linear sensitivity J againstthe finite difference approximation

    1

    2

    J(+) J()

    .

    Typical results from such a check are shown in Figure6. For extremely small values of , the dominant

    error is due to machine accuracy in computing J()and has a magnitude which is O(/) where hererepresents the level of machine accuracy. For largervalues of , the dominant error is O(2) due tothe second order accuracy of central finite differences.

    1010

    108

    106

    104

    102

    100

    108

    106

    104

    102

    relativ

    e

    error

    Fig.6: Relative error in finite difference sensitivity asa function of the step size .

  • 7/30/2019 Bangalore 05

    9/9

    Using Automatic Differentiation for Adjoint CFD Code Development 9

    6 Conclusions

    Although the example application in this paper is verysimple, the same approach is also being used for a set

    of turbomachinery codes called HYDRA. HYDRA in-cludes a nonlinear analysis code [17], a linear code forthe analysis of flutter and unsteady forced response[3], and an adjoint code for design optimisation [9].The use of Tapenade is essential in keeping the linearand adjoint codes consistent with the latest changesto the nonlinear code, and Tapenade handles with-out any difficulty the complicated nonlinearities andconditional branching in the turbulence modelling andthe characteristic-based numerical smoothing. As inthe model application, an extensive set of validationchecks is employed to verify the correctness of the lin-ear and adjoint routines and codes.

    It is our hope that the mathematical overview andsoftware development process outlined in this paperwill help and encourage those who are interested indeveloping industrial scale adjoint codes for design op-timisation. It is strongly recommended that those whoare interested in this should download the source codeand Makefile [10] and obtain a copy of Tapenade [13]in order to try out the codes and run through thewhole development process and validation checks.

    Acknowledgements

    This research was performed as part of the MCDOproject funded by the UK Department for Trade andIndustry and Rolls-Royce plc, and coordinated byYoon Ho, Leigh Lapworth and Shahrokh Shahpar.

    We are very grateful to Laurent Hascoet for makingTapenade available to us, and for being so responsiveto our queries.

    REFERENCES

    [1] W.K. Anderson and D.L. Bonhaus. Airfoil designon unstructured grids for turbulent flows. AIAAJ., 37(2):185191, 1999.

    [2] W.K. Anderson and E. Nielsen. Sensitivity anal-ysis for Navier-Stokes equations on unstructuredgrids using complex variables. AIAA J., 39(1):56

    63, 2001.[3] M.S. Campobasso and M.B. Giles. Effect of flowinstabilities on the linear analysis of turboma-chinery aeroelasticity. AIAA J. Propulsion andPower, 19(2), 2003.

    [4] F. Courty, A. Dervieux, B. Koobus, and L. Has-coet. Reverse automatic differentiation for op-timum design: from adjoint state assembly togradient computation. Opt. Meth. and Software,18(5):615627, 2003.

    [5] J. Elliott and J. Peraire. Practical 3D aerody-namic design and optimization using unstructured

    meshes. AIAA J., 35(9):14791485, 1997.[6] R. Giering and T. Kaminski. Recipes for adjoint

    code construction. ACM Trans. Math. Software,24(4):437474, 1998.

    [7] M.B. Giles. On the use of Runge-Kutta time-marching and multigrid for the solution of steadyadjoint equations. Technical Report NA00/10,Oxford University Computing Laboratory, 2000.

    [8] M.B. Giles. On the iterative solution of adjointequations. In G. Corliss, C. Faure, A. Griewank,L. Hascoet, and U. Naumann, editors, AutomaticDifferentiation: From Simulation to Optimiza-tion, pages 145152. Springer-Verlag, 2001.

    [9] M.B. Giles, M.C. Duta, J.-D. Muller, and N.A.Pierce. Algorithm developments for discrete ad-joint methods. AIAA J., 42(2), 2003.

    [10] M.B. Giles and D. Ghate. Source code for

    airfoil testcase for forward and reverse modeautomatic differentiation using Tapenade, 2005.http://www.comlab.ox.ac.uk/mike.giles/airfoil/.

    [11] A. Griewank. Evaluating derivatives : princi-ples and techniques of algorithmic differentiation.SIAM, 2000.

    [12] A. Griewank, D. Juedes, and J. Utke. ADOL-C:a package for the automatic differentiation of al-gorithms written in C/C++. ACM Trans. Math.Software, 22(2):437474, 1996.

    [13] L. Hascoet and V. Pascual. Tapenade 2.1 usersguide. Technical Report 0300, INRIA, 2004http://www-sop.inria.fr/tropics/.

    [14] A. Jameson. Aerodynamic design via control the-ory. J. Sci. Comput., 3:233260, 1988.

    [15] A. Jameson, N. Pierce, and L. Martinelli. Opti-mum aerodynamic design using the Navier-Stokesequations. J. Theor. Comp. Fluid Mech., 10:213237, 1998.

    [16] B. Mohammadi and O. Pironneau. Mesh adap-tion and automatic differentiation in a CAD-freeframework for optimal shape design. Internat. J.Numer. Methods Fluids, 30(2):127136, 1999.

    [17] P. Moinier, J.-D. Muller, and M.B. Giles. Edge-based multigrid and preconditioning for hybridgrids. AIAA J., 40(10):19541960, 2002.

    [18] O. Pironneau. On optimum design in fluid me-chanics. J. Fluid Mech., 64:97110, 1974.[19] J. Reuther, A. Jameson, J.J. Alonso, M.J. Rem-

    linger, and D. Saunders. Constrained multipointaerodynamic shape optimisation using an adjointformulation and parallel computers, parts 1 and2. J. Aircraft, 36(1):5174, 1999.

    [20] W. Squire and G. Trapp. Using complex variablesto estimate derivatives of real functions. SIAMRev., 10(1):110112, 1998.