Exercise 2: Plaquette
Goals: Develop plaquette code
Concepts: Parallel variables, parallel operations, shifts, reduction
Directory: $HOME/examples/02-plaquette
How to: $ cd $HOME/examples/02-plaquette
$ make
$ submit plaquette

Let us start with the main procedure. In file main.c we define a 4-d gauge field on a lattice on line 11, allocate memory for it on line 30 and set it to unit on line 31. We also compute the lattice volume in lines 22-23:

 11     QDP_ColorMatrix *U[NDIM];
...
21 /* compute lattice volume */
22 for (volume = 1, mu = 0; mu < NDIM; mu++)
23 volume *= QDP_coord_size(mu);
24
25 /* allocate the gauge field and set it to unit */
26 for (mu = 0; mu < NDIM; mu++) {
27 QLA_Complex one;
28 QLA_c_eq_r(one, 1.0);
29
30 U[mu] = QDP_create_M();
31 QDP_M_eq_c(U[mu], &one, QDP_all);
32 }

At this point we are ready to compute the plaquette. Since we are going to use the plaquette often, it is profitable to abtract the computation into a function. Notice that a parallel variable is passed as argument to plaquette() at line 34. As far as C is concerned, there is nothing special about QDP objects - they could be declared both global and local, assigned to each other, their address could be taken, they could passed as arguments to functions, and returned from procedures.

 34     /* Compute plaquette */
35 plaq = plaquette(U);

When we do not need a QDP object any more, it should be explicitly destroyed, see line 38.

 37     /* delete the gauge field */
38 for (mu = 0; mu < NDIM; mu++) QDP_destroy_M(U[mu]);

The rest of main() prints the computed value of the plaquette and terminates QDP. Now let us take a look at plaquette.c. To compute the plaquette we need four temporary QDP objects which are declared on lines 8-11 and created on lines 15-18.

  1   #include <qdp-config.h>
2
3 QLA_Real
4 plaquette(QDP_ColorMatrix *link[])
5 {
6 int mu, nu;
7 QLA_Real plaq, total;
8 QDP_ColorMatrix *tmp1;
9 QDP_ColorMatrix *tmp2;
10 QDP_ColorMatrix *tmp3;
11 QDP_ColorMatrix *tmp4;
12
13 total = 0;
14
15 tmp1 = QDP_create_M();
16 tmp2 = QDP_create_M();
17 tmp3 = QDP_create_M();
18 tmp4 = QDP_create_M();

To compute a plaquette in the 2-plane (μ,ν) we shift the field U[ν] in the direction μ from the forward neighbor on line 22, shift the field U[μ] in the direction ν from the forward neighbor on line 23, compute the local "elbow" on line 24, then multiply by the first shifted field U[ν] on line 25, and combine this with the second shifted field U[μ] into a plaquette and sum the value over the lattice on line 26. We combine the plaquette values for different (μ,ν) on line 27. For the time being the last argument to QDP calls, QDP_all, is magic. We will talk more about it in Exercise 5.

 20     for (mu = 0; mu < NDIM; mu++) {
21 for (nu = mu + 1; nu < NDIM; nu++) {
22 QDP_M_eq_sM(tmp1, link[nu], QDP_neighbor[mu], QDP_forward,
QDP_all);
23 QDP_M_eq_sM(tmp2, link[mu], QDP_neighbor[nu], QDP_forward,
QDP_all);
24 QDP_M_eq_Ma_times_M(tmp3, link[nu], link[mu],
QDP_all);
25 QDP_M_eq_M_times_M(tmp4, tmp3, tmp1,
QDP_all);
26 QDP_r_eq_re_M_dot_M(&plaq, tmp2, tmp4,
QDP_all);
27 total += plaq;
28 }
29 }

Once the computation is done, we destroy the temporaries on lines 31-34.

 31     QDP_destroy_M(tmp1);
32 QDP_destroy_M(tmp2);
33 QDP_destroy_M(tmp3);
34 QDP_destroy_M(tmp4);
35
36 return total;
37 }

You probably noticed that there is a system in naming of QDP functions. The full explanation can be found in the QDP specification.  Here we summarize the part that we are going to use in the exercises.

<function-name> ::= QDP_<res>_<assign>_<arg>
<function-name> ::= QDP_<res>_<assign>_<arg>_<op>_<arg>
<res> ::= <type>
<arg> ::= <shift><type><conjugation>

no shift
s shift controlled by two extra arguments

no conjugation
a hermitian conjugation

eq a = b a = b <op> c
peq a = a + b a = a + b <op> c
meq a = a - b a = a - b <op> c
eqm a = - b a = - b <op> c

i QLA_Int I QDP_Int
r QLA_Real R QDP_Real
c QLA_Complex C QDP_Complex
S QDP_RandomState
M QDP_ColorMatrix
D QDP_DiracFermion
P QDP_DiracPropagator