/****************************************************************
 * MIMD SU3 - adjoint Higgs                                     *
 *                                                              *
 *     Measurement routines                                     *
 *     Kari Rummukainen 1992 - 1996                             *
 *                                                              *
 ***************************************************************/

#include "lattice.h"    /* global variables for lattice fields */


typedef struct {
  int headerid,headersize;
  int n_double,n_long,n_float,n_char;
  int lx,ly,lz,lt;
  int d1,d2,d3,d4,d5,d6,d7,d8;
} e_header;
#define E_HEADER_ID 91919191

static FILE *measfile, *corrfile;

#ifdef HIGGS
#define m_plaq 1
#define m_hopp 2
#define m_a    3
#define m_a2   4
#define m_a3   5
#define m_a4   6
#define m_acty 7
#define N_MEAS 8
#elif NDIM == 3
#define m_plaq 0
#define N_MEAS 1
#elif NDIM == 4
#define m_plaq_s 0
#define m_plaq_t 1
#define ploop_r  2
#define ploop_i  3
#define N_MEAS 4
#endif
double ma[N_MEAS];

void measure_plaq();
void measure_higgs();
int reposition(FILE *f,int nmeas);

void 
measure()
{
  int i;
  complex ct;

  for (i=0; i<N_MEAS; i++) ma[i] = 0;

  measure_plaq();
#ifdef HIGGS
  measure_higgs();
#endif

#if NDIM == 4
  ct = measure_ploop(U, TUP);
  ma[ploop_r] = ct.real;
  ma[ploop_i] = ct.imag;
#endif

}

/************************************************************
 *                                                          *
 *     calculate a staple                                   *
 *                                                          *
 ***********************************************************/

void
measure_plaq()
{
  /*     first, collect the staples, and multiply
   *
   *                  + C +
   *                  X   B
   *                  + A +
   */

  msg_tag *tag0,*tag1;
  int i,dir1,dir2;
  radix plaq;
  su3_matrix a, b;

  for (dir1=0; dir1<NDIM-1; dir1++) for (dir2=dir1+1; dir2<NDIM; dir2++) {
    /* collect forward plaquettes */
    
    tag0 = start_get( U[dir2], dir1, EVENODD );
    tag1 = start_get( U[dir1], dir2, EVENODD );

    forallsites_wait2(i,tag0,tag1) {
      mult_su3_an( &U[dir2][i], &U[dir1][i], &b );
      mult_su3_na( &U[dir1][nb(dir2,i)], &U[dir2][nb(dir1,i)], &a);
      plaq = 1.0 - (1.0/3.0)*realtrace_su3(&b, &a);
#if NDIM == 3
      ma[m_plaq] += plaq;
#else
      if (dir2 == TUP) ma[m_plaq_t] += plaq;
      else             ma[m_plaq_s] += plaq;
#endif
    }
  }

#if NDIM == 3
  ma[m_plaq] /= 3*lattice.volume;
#else
  ma[m_plaq_s] /= 3*lattice.volume;
  ma[m_plaq_t] /= 3*lattice.volume;
#endif
}
  
/****************************************************************
 *                                                              *
 *     this subroutine calculates the hopping terms and radial  *
 *     contributions for the                                    *
 *     adjoint Higgs field                                      *
 *                                                              *
 ***************************************************************/

#ifdef HIGGS

void measure_higgs()
{
  /*     X |-- UF --> F
   *
   *     action is -1/2 beta Tr(X' UF) = -1/2 beta Tr(X F'U')
   *
   *     Multiply and add RF*VF'*UF'
   *
   *     GF: Now B,X,F = 1;
   */


  msg_tag *tag[NDIM];
  int i,j,dir;
  double r2;
  su3_matrix a1,a2;
  
  /* start gathers of points up */
  foralldir(dir) tag[dir] = start_get( ahiggs, dir, EVENODD );
  
  forallsites_waitA(i,tag,NDIM) {
    uncompress_adjmat( &ahiggs[i], &a1);
    
    foralldir(dir) 
      ma[m_hopp] += act_gauge_adj(&a1, &U[dir][i], &ahiggs[nb(dir,i)]);

    for (r2=j=0; j<8; j++) r2 +=  sqr( ahiggs[i].l[j] ); 
    
    ma[m_a2] += r2;
    ma[m_a4] += r2*r2;
    
    ma[m_a]  += sqrt(r2);

    /* and then A0^3  -- 
     * NOTE: now Tr(A^3)_cont = Tr(A^3)_latt * 2^(3/2)
     * and below it is also divided by 3!  
     */
    mult_su3_nn( &a1, &a1, &a2);
    ma[m_a3] += realtrace_su3( &a2, &a1);  /* this is a2' * a1, but a2 
					      is hermitean */
  }

  ma[m_acty] = ma[m_a2] * betay;

  ma[m_hopp]  /= 3*lattice.volume*(2.0*betaA);
  ma[m_a]     /= lattice.volume;
  ma[m_a2]    /= lattice.volume;
  ma[m_a3]    /= 3*lattice.volume;
  ma[m_a4]    /= lattice.volume;
}

#endif

/************************************************************
 * write measurements
 */

void
writemeas()
{
  int i;

  /* sum it */
  g_vecdoublesum(ma, N_MEAS, 0);

  if (this_node == 0) {
#ifdef HIGGS
    if (is_multicanonical ) ma[0] = multi_weight();
#endif

    meas_sync++;
    i = (fwrite(ma,sizeof(double),N_MEAS,measfile) == N_MEAS);
    if (i) i = (fwrite(&meas_sync,sizeof(int),1,measfile) == 1);

    if (!i) halt("Could not write measurement file");

    if (meas_sync % 100 == 0) fflush(measfile);
  }
}

#ifdef HIGGS

/************************************************************
 * write correlations
 */

void
writecorr()
{
  int i,j;

  corr_sync++;
  
  if (this_node == 0) {
    for (j=0; j<n_corr*corrlen; j++) 
      c_array[j] /= (w_correlation/n_correlation);
    
    i = (fwrite(c_array,sizeof(float),n_corr*corrlen,corrfile)
	 == n_corr*corrlen);

    if (i) i = (fwrite(&corr_sync,sizeof(int),1,corrfile) == 1);
    if (!i) halt("Could not write correlation file");

    for (j=0; j<n_corr*corrlen; j++) c_array[j] = 0.0;

    fflush(corrfile);
  }
}

#endif

/**************************************************
 * Set up the system for one run
 */

void
setfiles(int restart)
{
  e_header h;

#ifdef HIGGS
  corrlen = lattice.size[ZUP]/2 + 1;
#endif
  if (this_node == 0) {
    if (!restart) {

      h.headerid = E_HEADER_ID;
      h.headersize = sizeof(e_header);

      h.lx = lattice.size[XUP]; h.ly = lattice.size[YUP]; 
      h.lz = lattice.size[ZUP]; h.lt = 1;
#if NDIM == 4
      h.lt = lattice.size[TUP];
#endif

      h.n_double = N_MEAS;
      h.n_long = h.n_float = h.n_char = 0;

      measfile = fopen(measurename,"w+");
      fwrite(&h,sizeof(e_header),1,measfile);
      meas_sync = 0;

#ifdef HIGGS
      h.n_float = corrlen*n_corr;
      h.d1 = n_corr;               /* number of correlations */
      h.d2 = corrlen;              /* length */

      corrfile = fopen(corrname,"w+");
      fwrite(&h,sizeof(e_header),1,corrfile);
      corr_sync = 0;
      fflush(corrfile);
#endif

    } else {

      measfile = fopen(measurename,"r+");
      if (measfile == NULL) halt("Measurement file?");
      meas_sync = reposition(measfile,iteration/n_measurement);

#ifdef HIGGS
      corrfile = fopen(corrname,"r+");
      if (corrfile == NULL) halt("Correlation file?");
      corr_sync = reposition(corrfile,iteration/w_correlation);
      fflush(corrfile);
#endif

      printf(" - Repositioning to sweep %d\n",iteration);

    }
  } /* this_node == 0 */
}

/**************************************************
 * this routine repositions the measurement-files
 */

int reposition(FILE *f,int nmeas)
{
  e_header h;
  int length;
  int l,j;
  char *cbuf;

  fread(&h,sizeof(e_header),1,f);
  j = 0;
  length = h.n_double*sizeof(double) +
    h.n_long*sizeof(long) + h.n_float*sizeof(float) +h.n_char*sizeof(char);
  cbuf = (char *)malloc(length);

  while (j<nmeas) {
    fread(cbuf,sizeof(char),length,f);
    fread(&l,sizeof(int),1,f);
    if (l != ++j) {
      printf(" block %d, flag %d\n",j,l);
      halt(" *** sync error in file");
    }
  }
  free(cbuf);

  /* also flush the file - just in case */
  l = ftell(f);
  fflush(f);
  fseek(f,l,SEEK_SET);

  return(j);
}


/****************************************************************
 *                                                              *
 *     dumpall saves the data in a restartable format.          *
 *     also checks if the max-iter has changed.                 *
 *                                                              *
 ***************************************************************/

void
dumpall(int status,int * maxiters)
{
  int restart;
  FILE * fil;
  double t;
  int nn_i,nn_t;
  int iseed;
  static int pm=0;

  if (n_save > 0) {
    if (this_node == 0) fil = fopen(confname,"w");
    t = cputime();
    save_binary(fil);
  }  

  if(this_node == 0){
    printf("+"); 
    pm++; if (pm >= 20) { printf(" iteration %d\n",iteration); pm = 0; }
    fflush(stdout);
    if (n_save > 0) fclose(fil);
  }

  if (this_node == 0) fil = fopen(statname,"r");
  restart      = get_i(fil,"restart",-1);
  nn_i         = get_i(fil,"n_iteration",-1);
  nn_t         = get_i(fil,"n_thermal",-1);
  if ((nn_i != n_iteration || nn_t != n_thermal)) {
    printf0(" -> New limits:thermal %d, work %d\n",nn_t,nn_i);
    n_iteration = nn_i;
    n_thermal = nn_t;

    if (status == 1) *maxiters = n_thermal;
    else *maxiters = n_iteration;
  }

  if (this_node == 0) fclose(fil);

  if (this_node == 0) {

    /* flush the files .. */    
    /* if (fflush(measfile) != 0) halt(" FILE ERROR when flushing measurements");
     */
    /* if (fflush(corrfil) != 0) halt(" FILE ERROR when flushing correlations");
     */

    fil = fopen(statname,"w");
    iseed = dran()*(1<<30);

    print_i(fil,"restart",1);     /* write now restart */
    print_i(fil,"n_iteration",n_iteration);
    print_i(fil,"n_thermal",n_thermal);
    print_i(fil,"seed",iseed);

    print_i(fil,"run status",status);
    print_i(fil,"iteration",iteration);
    print_d(fil,"time: gauge",timeu);
#ifdef HIGGS
    print_d(fil,"time: higgs",timea);
#endif
    print_d(fil,"time: rest",timerest);

    fclose(fil);

#ifdef HIGGS
    if (is_mucacalc) writemuca();
#endif

    fflush(stdout);
  }
}

#ifdef check

/****************************************************************
 *                                                              *
 *     check the terms ... diagnostic routine                   *
 *                                                              *
 ***************************************************************/

static double car[N_MEAS],car2[N_MEAS];
static int ii=0;

int
check_action(int stat)
{
  static double arr[N_MEAS];
  int i;

  measure();
  if (stat == 0) {
    for (i=0; i<N_MEAS; i++) arr[i]  = ma[i];
  } else {
    for (i=0; i<N_MEAS; i++) arr[i] -= ma[i];
    ii++;

    for (i=0; i<N_MEAS; i++) {
      car[i] += arr[i];
      car2[i] += sqr(arr[i]);
    }
  }
}

int
print_check()
{
  int i;

  for (i=0; i<N_MEAS; i++) {
    printf("%d :  %g +- %g\n",i,car[i]/ii,
	   sqrt(fabs(car2[i]/ii - sqr(car[i]/ii))/ii));
  }
}

#endif



