• No results found

One very similar element between all of the code generators is the generation of the code to perform an equation evaluation. The syntax for fetching values from memory will vary between different target generators, however the actual calculation string will be very similar if not identical for many of them. The computation string can be easily generated by performing an in-order traversal of the tree and outputting each node as appropriate. The Cahn-Hilliard equation is used as an example; the simulation tree for a Cahn-Hilliard simulation using the Euler method is shown in the previ- ous chapter in Figure 8.9. When this tree is traversed using an inorder traversal, the output string produced will be:

u_1 = u_0 + M*((-B*Laplacian(u_0) + U*Laplacian(u_0*u_0*u_0))-K*Laplacian 2(u_0))

Each of the parameters M, B, U and K can be directly referenced by its name but the lattice and stencil nodes are somewhat more complicated. Different languages will have different indexing and addressing schemes; even within the same language there are sometimes multiple ways to create and index arrays. Because each cell in the lattice must be updated, each of the nodes in the equation tree corresponding to a lattice will be replaced with the lattice name and the index into that lattice using an appropriate indexing scheme. The index values and scheme will depend on the specifics of that code generator and the algorithm it is implementing.

The code produced to apply a stencil to a lattice depends on the dimensionality of the simu- lation being generated. The output generator will examine the stencil matrix to determine which neighbouring values must be used in the calculation and what weights should be applied to them.

Using the index notation of u[x,y], the stencilLaplacian(u)(see Chapter 8 for the Laplacian stencil

matrix) will be expanded in two dimensions to:

u[x,y-1]+u[x-1,y]-4*u[x,y]+u[x+1,y]+u[x,y+1]

or in three dimensions to:

u[x,y,z-1]+u[x,y-1,z]+u[x-1,y,z]-6*u[x,y,z]+u[x+1,y,z]+u[x,y+1,z]+u[x,y,z+1]

Using these techniques, the code to compute the update of a single cell in the lattice can be con- structed by substituting these stencil expansions into the stencils in the output string. All the deci- sions on precision, syntax and semantics of the equation calculation are made by the code generator during this step. The tree is traversed by recursively processing each node in the tree. Each node in

9.2. EQUATION GENERATION

the tree has a membervaluewhich is the contents of the node and two childrenlef tandrightwhich

may or may not be used. The recursive algorithm for generating code by traversing an equation tree is given in Algorithm 3.

Algorithm 3Pseudo code for generating equation code from a tree.

process(Noden)

ifnis aparameterthen generatevalue

else ifnis aconstantthen generatevalue

else ifnis aoperatorthen iflef t=nullthen

generate”(” process(lef t) ”)”

end if

generatevalue

generate”(” process(right) ”)”

else ifnis alatticethen

determine[index]based on index scheme and stencil

generatevalue[index]

else ifnis astencilthen

array←value

for allcellinarraydo ifcell= 0then

generatecell”*” ”(” process(right) ”)”

end if

ifnot first valuethen

generate”+”

end if end for end if

The application of this algorithm to the Cahn-Hilliard, Ginzburg-Landau and Lotka-Volterra equation trees can be used to generate the code to compute the equations. The exact form of the algo- rithm given in Algorithm 3 will produce equation code using infix notation and standard operators. This is suitable for C-based languages such as those discussed in Chapter 4. However, alternative algorithms can easily be developed to produce code for any language or notation scheme.

9.2.1

Example Generated Equation Code

The following code listings 9.1, 9.2 and 9.3 show the C-syntax code generated by applying the al- gorithm described in Algorithm 3 to the equation trees of the Cahn-Hilliard, Ginzburg-Landau and Lotka-Volterra models. These equation trees are given in Chapter 8 and have been constructed from the ASCII representations of the models given in Chapter 7.

First the generated code for the Cahn-Hilliard model is shown in Listing 9.1. The example shows

the calculation of the Cahn-Hilliard model in two-dimensions and the naming conventionu0yxis

used to show the value fetched from the latticeu0at position(x,y). The code can be compared

CHAPTER 9. AUTOMATIC CODE GENERATION

has more parentheses which makes it slightly less reader-friendly, but this could be improved with relatively minor changes to the generator.

Listing 9.1: Generated C code that calculates the Cahn-Hilliard equation. ( ( (M((((B )( ( u0ym1x ) +

( u0yxm1 ) + (4u0yx ) + ( u0yxp1 ) + ( u0yp1x ) ) )

+(U( ( ( u0ym1xu0ym1x)u0ym1x ) +

( ( u0yxm1u0yxm1)u0yxm1 ) + (4(u0yxu0yx )u0yx ) + ( ( u0yxp1u0yxp1 )u0yxp1 ) + ( ( u0yp1xu0yp1x )u0yp1x ) ) ) )

(K( ( u0ym2x ) +

(2u0ym1xm1 ) + (8u0ym1x ) + (2u0ym1xp1 ) +

( u0yxm2 ) + (8u0yxm1 ) + (20u0yx ) + (8u0yxp1 ) + ( u0yxp2 ) + (2u0yp1xm1 ) + (8u0yp1x ) + (2u0yp1xp1 ) +

( u0yp2x ) ) ) ) ) )

Listing 9.2 shows the code produced by STARGATES that computes the Ginzburg-Landau model. This particular code listing computes the Ginzburg-Landau model as a single equation of type com-

plex. It assumes that a typecomplexwill be provided with support for the operations+,-,*,/and

abs().This code fragment can also be compared to the hand-crafted version in Chapter 5.

Listing 9.2: Generated C code that calculates the Ginzburg-Landau equation. ( ( ( ( (( P/ i ) )( ( u0ym1x ) +

( u0yxm1 ) + (4u0yx ) + ( u0yxp1 ) + ( u0yp1x ) ) )

( ( ( (Q/ i )( abs ( u0yx ) ) )( abs ( u0yx ) ) )u0yx ) ) + ( yu0yx ) ) )

Finally the generated code to compute the Lotka-Volterra model is given in Listing 9.3. This

code example has two latticesu00andu01that are used in the calculation of both of the governing

equations.

Listing 9.3: Generated C code that calculates the Lotka-Volterra equation. ( ( ( ( ( Au00yx)

( ( Bu00yx )u10yx ) ) +

( D0( ( u00ym1x ) +

( u00yxm1 ) + (4u00yx ) + ( u00yxp1 ) + ( u00yp1x ) ) ) ) )

( ( ( ( ( ( Cu00yx )u10yx)

(Du10yx ) ) +

( D1( ( u10ym1x ) +

( u10yxm1 ) + (4u10yx ) + ( u10yxp1 ) + ( u10yp1x ) ) ) ) )

This type of equation tree traversal can be used to produce code to compute any equation that can be described using an equation tree. The code for computing the three different equations has been produced automatically from simple ASCII descriptions of the models. These generated code listings of the three equations act as proof of concept that code for different computational models can be automatically generated from simple descriptions.

9.3. GENERATING TARGET SPECIFIC CODE