#include #include #include #include #include #include #include #include #include #include #include CPS_START_NAMESPACE /*! takes the imaginary part of a matrix */ void AlgActionDensity::ZeroReal(Matrix& m) { /* Matrix temp; temp.Dagger( m ); m-=temp; m*=0.5;*/ //Replacing above with below gives a factor of 2 speedup for the entire smartrun: for(int i = 0; i < 3; i++) { Rcomplex & elem = m(i, i); elem = Rcomplex(0.0,elem.imag()); } for(int x = 0; x < 2; x++) { for(int y = x+1; y < 3; y++) { Rcomplex & mxy = m(x, y); Rcomplex & myx = m(y, x); Float a = mxy.real(); Float b = mxy.imag(); Float c = myx.real(); Float d = myx.imag(); mxy = Rcomplex( 0.5 * (a - c), 0.5 * (b + d) ); myx = Rcomplex( 0.5 * (c - a), 0.5 * (b + d) ); } } } /*! Computes (1/2) tr(F_mu_nu F_mu_nu) Input should be a set of six matrices giving the field strength tensor F_mu_nu in each direction: clovers[0] = F_01 clovers[1] = F_02 clovers[2] = F_03 clovers[3] = F_12 clovers[4] = F_13 clovers[5] = F_23 */ Complex AlgActionDensity::ActionDensity(Matrix clovers[]) { Matrix action; action.ZeroMatrix(); for(int i = 0; i < 6; i++) { action.DotMPlus(clovers[i], clovers[i]); } //Minus sign accounts for the fact that that the input is actual i*F_mu_nu return -action.Tr(); } /*! Calculate Clover leaf (1x1 size) SU(3) Matrix Sheikholeslami, Wohlert, NPB259, 572 (1985) Eq. (2.9) */ void AlgActionDensity::CloverLeaf(Lattice& lattice, Matrix& pl, int* pos, int mu, int nu) { Matrix P0,P1,P2,P3; P0.ZeroMatrix(); P1.ZeroMatrix(); P2.ZeroMatrix(); P3.ZeroMatrix(); // each direction could be {0,1,2,3,4,5,6,7} coresponding to // the directions {n_x, n_y, n_z, n_t, -n_x, -n_y, -n_z, -n_t} int dirs0[4]={mu,nu, mu+4, nu+4}; lattice.PathOrdProdPlus(P0, pos, dirs0, 4); int dirs1[4]={nu+4,mu+4, nu, mu}; lattice.PathOrdProdPlus(P1, pos, dirs1, 4); int dirs2[4]={nu,mu+4, nu+4, mu}; lattice.PathOrdProdPlus(P2, pos, dirs2, 4); int dirs3[4]={mu,nu+4, mu+4, nu}; lattice.PathOrdProdPlus(P3, pos, dirs3, 4); P0 -= P1; P0 += P2; P0 -= P3; P0 *= 0.25; moveMem((Float*) &pl,(Float*) &P0, 18 * sizeof(Float) ); } void AlgActionDensity::run(Float *result) { Lattice& lattice( AlgLattice() ); Float action = 0; // sum over lattice Site nloop; while ( nloop.LoopsOverNode() ) { // Array of imaginary parts of the plaquettes // at a given site // clovers[0] = F_01 // clovers[1] = F_02 // clovers[2] = F_03 // clovers[3] = F_12 // clovers[4] = F_13 // clovers[5] = F_23 Matrix clovers[6]; // // fill clovers, then zero the real parts // int mu; int nu; int index(0); for (mu=0;mu<3;++mu) { for (nu=mu+1;nu<4;nu++) { CloverLeaf( lattice, clovers[index], nloop.pos(), mu, nu ); ZeroReal(clovers[index]); index++; } } action += ActionDensity(clovers).real(); } // global sum the approximations glb_sum(&action); Float action_density = action / GJP.VolSites(); if(result!=NULL) *result = action_density; // Print out results //---------------------------------------------------------------- if(common_arg->filename != 0) { const char *fname = "run()"; FILE *fp; if( (fp = Fopen(common_arg->filename, "a")) == NULL ) { ERR.FileA(cname,fname,common_arg->filename); } //Prints mean value of (1/2)tr(F_mu_nu F_mu_nu), in units of a^4 Fprintf(fp, "%15e\n", action_density); Fclose(fp); } } inline Float * AlgActionDensity::GsiteOffset(Float * p, const int *x, const int *g_dir_offset) { return p + x[0] * g_dir_offset[0] + x[1] * g_dir_offset[1] + x[2] * g_dir_offset[2] + x[3] * g_dir_offset[3]; } void AlgActionDensity::PathOrdProd(Matrix & mat, int* x, int* dirs, int n, Float *gfield, int *g_dir_offset) { int abs_dir; int dir_sign; int link_site[4]; const int MatrixSize = 18; const Matrix * p1; int i; for(i = 0; i < 4; ++i) link_site[i] = x[i]; //deal with the first link //abs_dir is {0,1,2,3} //dir_sign is {0 = positive, 1 = negative} //------------------------------ abs_dir = dirs[0] & 3; dir_sign = dirs[0] >> 2; //if dir_sign == 1, the link is at x-n_v link_site[abs_dir] -= dir_sign; //p1 = GetBufferedLink(link_site, abs_dir); //get the first link p1 = (Matrix*) GsiteOffset(gfield, link_site, g_dir_offset) + abs_dir; //if dir_sign == 0, march on to the next site, //if dir_sign == 1, we have already moved. link_site[abs_dir] += 1 - dir_sign; //Temporary matrices and ther pointers Matrix ma, mb, mc; Matrix *pma = &ma; Matrix *pmb = &mb; Matrix *pmc = &mc; //if dir_sign==1 the link is going backward so get its dagger if(dir_sign) pma -> Dagger((IFloat*)p1); else memcpy((IFloat*)pma, (IFloat*)p1, MatrixSize * sizeof(IFloat)); for(i = 1; i < n; ++i) { abs_dir = dirs[i]&3; dir_sign = dirs[i]>>2; link_site[abs_dir] -= dir_sign; p1 = (Matrix*) GsiteOffset(gfield, link_site, g_dir_offset) + abs_dir; link_site[abs_dir] += 1 - dir_sign; //put the next link on the path in mb //-------------------------------------- if(dir_sign) mb.Dagger((IFloat*)p1); else memcpy((IFloat*)pmb, (IFloat*)p1, MatrixSize * sizeof(IFloat)); // if not the last link on the path, just multiply to the earlier result // mc = ma * mb // if the last link, multiply and add to mat if(i != n - 1) mDotMEqual((IFloat*)pmc, (IFloat*)pma, (IFloat*)pmb); else mDotMPlus((IFloat*)&mat, (IFloat*)pma, (IFloat*)pmb); //swap pma and pmc; Matrix * tmp_p = pma; pma = pmc; pmc = tmp_p; } } // ------------------------------------------------------------------ // each direction could be {0,1,2,3,4,5,6,7} coresponding to // the directions {n_x, n_y, n_z, n_t, -n_x, -n_y, -n_z, -n_t} // ------------------------------------------------------------------ /*! Calculate Clover leaf (1x1 size) SU(3) Matrix Sheikholeslami, Wohlert, NPB259, 572 (1985) Eq. (2.9) */ void AlgActionDensity::CloverLeaf(Matrix& pl, int* pos, int mu, int nu, Float *gfield, int *g_dir_offset) { Matrix P0, P1, P2, P3; P0.ZeroMatrix(); P1.ZeroMatrix(); P2.ZeroMatrix(); P3.ZeroMatrix(); int dirs0[4] = {mu, nu, mu + 4, nu + 4}; int dirs1[4] = {nu + 4, mu + 4, nu, mu}; int dirs2[4] = {nu, mu + 4, nu + 4, mu}; int dirs3[4] = {mu, nu + 4, mu + 4, nu}; PathOrdProd(P0, pos, dirs0, 4, gfield, g_dir_offset); PathOrdProd(P1, pos, dirs1, 4, gfield, g_dir_offset); PathOrdProd(P2, pos, dirs2, 4, gfield, g_dir_offset); PathOrdProd(P3, pos, dirs3, 4, gfield, g_dir_offset); P0 -= P1; P0 += P2; P0 -= P3; P0 *= 0.25; memcpy((Float*) &pl, (Float*) &P0, 18 * sizeof(Float)); } // A communication efficient way of calculating the t-charge // Pass the surface slab to adjacent nodes once // Do all the calculation locally. // Issues: // Put the orignal lattice in the center of the local fields // Assemble/disemble a continuous memory containning all the // data before/after the communication // If local size is too small, we construct a larger local // volume and pass on the data to the next neighbor // Local size >= 2 & Slab = 3 // Twice as large on each dimension will suffice. void AlgActionDensity::smartrun(Float* result) { const char fname[] = "smartrun()"; Lattice& lat( AlgLattice() ); const int Slab = 1; //Expansion in each direction if(GJP.Gparity() && Slab!=1){ //In this case the local field is doubled up and I'm not sure my G-parity changes will work if(!UniqueID()) printf("AlgActionDensity::smartrun(Float* result) : Code not implemented to deal with surface slab sizes > 1\n"); exit(-1); } const int MatrixSize = 2 * lat.Colors() * lat.Colors(); const int GsiteSize = 4 * MatrixSize; int l_node_sites[4] = { GJP.XnodeSites(), GJP.YnodeSites(), GJP.ZnodeSites(), GJP.TnodeSites()}; int l_dir_offset[4]; l_dir_offset[0] = GsiteSize; l_dir_offset[1] = l_dir_offset[0] * l_node_sites[0]; l_dir_offset[2] = l_dir_offset[1] * l_node_sites[1]; l_dir_offset[3] = l_dir_offset[2] * l_node_sites[2]; int vol_node_sites = GJP.VolNodeSites(); int flag[4] = {0, 0, 0, 0}; //Flags for too small a local dimension // lfield for original local gauge field Float * lfield = (Float*) smalloc(cname, fname, "lfield", GsiteSize * vol_node_sites * sizeof(Float)); memcpy(lfield, (Float *)lat.GaugeField(), GsiteSize * vol_node_sites * sizeof(Float)); int x[4], y[4]; Float *g_offset; Float *l_offset; // If local dimension k < Slab, expand it to twice as large for(int k = 0; k < 4; ++k) { if(l_node_sites[k] >= Slab) continue; flag[k] = 1; Float * afield = (Float*) smalloc(cname, fname, "afield", GsiteSize * vol_node_sites * sizeof(Float)); getPlusData(afield, lfield, GsiteSize * vol_node_sites, k); if(GJP.Bc(k) == BND_CND_GPARITY && GJP.NodeCoor(k) == GJP.Nodes(k)-1) for(int f=1;ffilename != 0) { const char *fname = "run()"; FILE *fp; if( (fp = Fopen(common_arg->filename, "a")) == NULL ) { ERR.FileA(cname,fname,common_arg->filename); } //Prints mean value of (1/2)tr(F_mu_nu F_mu_nu), in units of a^4 Fprintf(fp, "%15e\n", action_density); Fclose(fp); } } CPS_END_NAMESPACE