https://github.com/to-ko/mesons
Raw File
Tip revision: 6dece129a649214f273f4526472c89958e169b7b authored by Tomasz Korzec on 23 September 2014, 12:17:49 UTC
mesons relase 1.2
Tip revision: 6dece12
mesons.c
/*******************************************************************************
*
* File mesons.c
*
* Copyright (C) 2013, 2014 Tomasz Korzec
*
* Based on openQCD, ms1 and ms4
* Copyright (C) 2012 Martin Luescher and Stefan Schaefer
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*******************************************************************************
*
* Computation of quark propagators
*
* Syntax: mesons -i <input file> [-noexp] [-a]
*
* For usage instructions see the file README.mesons
*
*******************************************************************************/

#define MAIN_PROGRAM

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "mpi.h"
#include "su3.h"
#include "random.h"
#include "flags.h"
#include "utils.h"
#include "lattice.h"
#include "archive.h"
#include "sflds.h"
#include "linalg.h"
#include "dirac.h"
#include "sap.h"
#include "dfl.h"
#include "forces.h"
#include "version.h"
#include "global.h"
#include "mesons.h"

#define N0 (NPROC0*L0)
#define N1 (NPROC1*L1)
#define N2 (NPROC2*L2)
#define N3 (NPROC3*L3)

static char line[NAME_SIZE+1];

#define MAX(n,m) \
   if ((n)<(m)) \
      (n)=(m)

static struct
{
   int ncorr;
   int nnoise;
   int tvals;
   int noisetype;
   double *kappa1;
   double *kappa2;
   int *type1;
   int *type2;
   int *x0;
   int *isreal;
} file_head;

static struct
{
   complex_dble *corr;
   complex_dble *corr_tmp;
   int nc;
} data;

static struct
{
   int nux0;     /* number of unique x0 values */
   int *ux0;     /* unique x0 values */
   int *nprop;   /* number of propagators at each x0 */
   int nmax;     /* max(nprop) */
   int **prop;   /* propagator index of each x0 and propagator */
   int **type;   /* type index of each x0 and propagator  */
} proplist;

static int my_rank,noexp,append,norng,endian;
static int first,last,step;
static int level,seed,nprop,ncorr,nnoise,noisetype,tvals;
static int *isps,*props1,*props2,*type1,*type2,*x0s;
static int ipgrd[2],*rlxs_state=NULL,*rlxd_state=NULL;
static double *kappas,*mus;


static char log_dir[NAME_SIZE],loc_dir[NAME_SIZE];
static char cnfg_dir[NAME_SIZE],dat_dir[NAME_SIZE];
static char log_file[NAME_SIZE],log_save[NAME_SIZE],end_file[NAME_SIZE];
static char dat_file[NAME_SIZE],dat_save[NAME_SIZE];
static char par_file[NAME_SIZE],par_save[NAME_SIZE];
static char rng_file[NAME_SIZE],rng_save[NAME_SIZE];
static char cnfg_file[NAME_SIZE],nbase[NAME_SIZE],outbase[NAME_SIZE];
static FILE *fin=NULL,*flog=NULL,*fend=NULL,*fdat=NULL;


static void alloc_data(void)
{
   data.corr=malloc(file_head.ncorr*file_head.nnoise*file_head.tvals*
                                                          sizeof(complex_dble));
   data.corr_tmp=malloc(file_head.ncorr*file_head.nnoise*file_head.tvals*
                                                      sizeof(complex_dble));
   error((data.corr==NULL)||(data.corr_tmp==NULL),1,"alloc_data [mesons.c]",
         "Unable to allocate data arrays");
}


static void write_file_head(void)
{
   stdint_t istd[1];
   int iw=0;
   int i;
   double dbl[1];

   istd[0]=(stdint_t)(file_head.ncorr);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   iw=fwrite(istd,sizeof(stdint_t),1,fdat);

   istd[0]=(stdint_t)(file_head.nnoise);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

   istd[0]=(stdint_t)(file_head.tvals);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

   istd[0]=(stdint_t)(file_head.noisetype);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

   error_root(iw!=4,1,"write_file_head [mesons.c]",
              "Incorrect write count");
   for (i=0;i<file_head.ncorr;i++)
   {
      dbl[0] = file_head.kappa1[i];
      if (endian==BIG_ENDIAN)
      bswap_double(1,dbl);
      iw=fwrite(dbl,sizeof(double),1,fdat);

      dbl[0] = file_head.kappa2[i];
      if (endian==BIG_ENDIAN)
      bswap_double(1,dbl);
      iw+=fwrite(dbl,sizeof(double),1,fdat);

      istd[0]=(stdint_t)(file_head.type1[i]);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

      istd[0]=(stdint_t)(file_head.type2[i]);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

      istd[0]=(stdint_t)(file_head.x0[i]);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

      istd[0]=(stdint_t)(file_head.isreal[i]);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      iw+=fwrite(istd,sizeof(stdint_t),1,fdat);

      error_root(iw!=6,1,"write_file_head [mesons.c]",
              "Incorrect write count");
   }
}

static void check_file_head(void)
{
   int i,ir,ie;
   stdint_t istd[1];
   double dbl[1];

   ir=fread(istd,sizeof(stdint_t),1,fdat);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   ie=(istd[0]!=(stdint_t)(file_head.ncorr));

   ir+=fread(istd,sizeof(stdint_t),1,fdat);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   ie+=(istd[0]!=(stdint_t)(file_head.nnoise));

   ir+=fread(istd,sizeof(stdint_t),1,fdat);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   ie+=(istd[0]!=(stdint_t)(file_head.tvals));

   ir+=fread(istd,sizeof(stdint_t),1,fdat);
   if (endian==BIG_ENDIAN)
      bswap_int(1,istd);
   ie+=(istd[0]!=(stdint_t)(file_head.noisetype));

   error_root(ir!=4,1,"check_file_head [mesons.c]",
              "Incorrect read count");
   error_root(ie!=0,1,"check_file_head [mesons.c]",
              "Unexpected value of ncorr, nnoise, tvals or noisetype");
   for (i=0;i<file_head.ncorr;i++)
   {
      ir=fread(dbl,sizeof(double),1,fdat);
      if (endian==BIG_ENDIAN)
      bswap_double(1,dbl);
      ie=(dbl[0]!=file_head.kappa1[i]);

      ir+=fread(dbl,sizeof(double),1,fdat);
      if (endian==BIG_ENDIAN)
      bswap_double(1,dbl);
      ie+=(dbl[0]!=file_head.kappa2[i]);

      ir+=fread(istd,sizeof(stdint_t),1,fdat);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      ie+=(istd[0]!=(stdint_t)(file_head.type1[i]));

      ir+=fread(istd,sizeof(stdint_t),1,fdat);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      ie+=(istd[0]!=(stdint_t)(file_head.type2[i]));

      ir+=fread(istd,sizeof(stdint_t),1,fdat);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      ie+=(istd[0]!=(stdint_t)(file_head.x0[i]));

      ir+=fread(istd,sizeof(stdint_t),1,fdat);
      if (endian==BIG_ENDIAN)
         bswap_int(1,istd);
      ie+=(istd[0]!=(stdint_t)(file_head.isreal[i]));

      error_root(ir!=6,1,"check_file_head [mesons.c]",
              "Incorrect read count");
      error_root(ie!=0,1,"check_file_head [mesons.c]",
              "Unexpected value of kappa, type, x0 or isreal");
   }
}

static void write_data(void)
{
   int iw;
   int nw;
   int chunk;
   int icorr,i;

   if (my_rank==0)
   {
      fdat=fopen(dat_file,"ab");
      error_root(fdat==NULL,1,"write_data [mesons.c]",
                 "Unable to open dat file");

      nw = 1;
      if(endian==BIG_ENDIAN)
      {
         bswap_double(file_head.nnoise*file_head.tvals*file_head.ncorr*2,
                      data.corr);
         bswap_int(1,&(data.nc));
      }
      iw=fwrite(&(data.nc),sizeof(int),1,fdat);
      for (icorr=0;icorr<file_head.ncorr;icorr++)
      {
         chunk=file_head.nnoise*file_head.tvals*(2-file_head.isreal[icorr]);
         nw+=chunk;
         if (file_head.isreal[icorr])
         {
            for (i=0;i<chunk;i++)
               iw+=fwrite(&(data.corr[icorr*file_head.tvals*file_head.nnoise+i]),
                       sizeof(double),1,fdat);
         }else
         {
            iw+=fwrite(&(data.corr[icorr*file_head.tvals*file_head.nnoise]),
                       sizeof(double),chunk,fdat);
         }
      }
      if(endian==BIG_ENDIAN)
      {
         bswap_double(file_head.nnoise*file_head.tvals*file_head.ncorr*2,
                      data.corr);
         bswap_int(1,&(data.nc));
      }
      error_root(iw!=nw,1,"write_data [mesons.c]",
                 "Incorrect write count");
      fclose(fdat);
   }
}

static int read_data(void)
{
   int ir;
   int nr;
   int chunk;
   int icorr,i;
   double zero;

   zero=0;
   if(endian==BIG_ENDIAN)
      bswap_double(1,&zero);
   nr=1;
   ir=fread(&(data.nc),sizeof(int),1,fdat);

   for (icorr=0;icorr<file_head.ncorr;icorr++)
   {
      chunk=file_head.nnoise*file_head.tvals*(2-file_head.isreal[icorr]);
      nr+=chunk;
      if (file_head.isreal[icorr])
      {
         for (i=0;i<chunk;i++)
         {
            ir+=fread(&(data.corr[icorr*file_head.tvals*file_head.nnoise+i]),
                    sizeof(double),1,fdat);
            data.corr[icorr*file_head.tvals*file_head.nnoise+i].im=zero;
         }
      }else
      {
         ir+=fread(&(data.corr[icorr*file_head.tvals*file_head.nnoise]),
                    sizeof(double),chunk,fdat);
      }
   }

   if (ir==0)
      return 0;

   error_root(ir!=nr,1,"read_data [mesons.c]",
                 "Read error or incomplete data record");
   if(endian==BIG_ENDIAN)
   {
      bswap_double(nr,data.corr);
      bswap_int(1,&(data.nc));
   }
   return 1;
}

static void read_dirs(void)
{
   if (my_rank==0)
   {
      find_section("Run name");
      read_line("name","%s",nbase);
      read_line_opt("output",nbase,"%s",outbase);

      find_section("Directories");
      read_line("log_dir","%s",log_dir);

      if (noexp)
      {
         read_line("loc_dir","%s",loc_dir);
         cnfg_dir[0]='\0';
      }
      else
      {
         read_line("cnfg_dir","%s",cnfg_dir);
         loc_dir[0]='\0';
      }

      read_line("dat_dir","%s",dat_dir);

      find_section("Configurations");
      read_line("first","%d",&first);
      read_line("last","%d",&last);
      read_line("step","%d",&step);

      find_section("Random number generator");
      read_line("level","%d",&level);
      read_line("seed","%d",&seed);

      error_root((last<first)||(step<1)||(((last-first)%step)!=0),1,
                 "read_dirs [mesons.c]","Improper configuration range");
   }

   MPI_Bcast(nbase,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);
   MPI_Bcast(outbase,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);

   MPI_Bcast(log_dir,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);
   MPI_Bcast(loc_dir,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);
   MPI_Bcast(cnfg_dir,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);
   MPI_Bcast(dat_dir,NAME_SIZE,MPI_CHAR,0,MPI_COMM_WORLD);

   MPI_Bcast(&first,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&last,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&step,1,MPI_INT,0,MPI_COMM_WORLD);

   MPI_Bcast(&level,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&seed,1,MPI_INT,0,MPI_COMM_WORLD);
}


static void setup_files(void)
{
   if (noexp)
      error_root(name_size("%s/%sn%d_%d",loc_dir,nbase,last,NPROC-1)>=NAME_SIZE,
                 1,"setup_files [mesons.c]","loc_dir name is too long");
   else
      error_root(name_size("%s/%sn%d",cnfg_dir,nbase,last)>=NAME_SIZE,
                 1,"setup_files [mesons.c]","cnfg_dir name is too long");

   check_dir_root(dat_dir);
   error_root(name_size("%s/%s.mesons.dat~",dat_dir,outbase)>=NAME_SIZE,
              1,"setup_files [mesons.c]","dat_dir name is too long");

   check_dir_root(log_dir);
   error_root(name_size("%s/%s.mesons.log~",log_dir,outbase)>=NAME_SIZE,
              1,"setup_files [mesons.c]","log_dir name is too long");

   sprintf(log_file,"%s/%s.mesons.log",log_dir,outbase);
   sprintf(end_file,"%s/%s.mesons.end",log_dir,outbase);
   sprintf(par_file,"%s/%s.mesons.par",dat_dir,outbase);
   sprintf(dat_file,"%s/%s.mesons.dat",dat_dir,outbase);
   sprintf(rng_file,"%s/%s.mesons.rng",dat_dir,outbase);
   sprintf(log_save,"%s~",log_file);
   sprintf(par_save,"%s~",par_file);
   sprintf(dat_save,"%s~",dat_file);
   sprintf(rng_save,"%s~",rng_file);
}


static void read_lat_parms(void)
{
   double csw,cF;
   char tmpstring[NAME_SIZE];
   char tmpstring2[NAME_SIZE];
   int iprop,icorr;

   if (my_rank==0)
   {
      find_section("Measurements");
      read_line("nprop","%d",&nprop);
      read_line("ncorr","%d",&ncorr);
      read_line("nnoise","%d",&nnoise);
      read_line("noise_type","%s",tmpstring);
      read_line("csw","%lf",&csw);
      read_line("cF","%lf",&cF);

      error_root(nprop<1,1,"read_lat_parms [mesons.c]",
                 "Specified nprop must be larger than zero");
      error_root(ncorr<1,1,"read_lat_parms [mesons.c]",
                 "Specified ncorr must be larger than zero");
      error_root(nnoise<1,1,"read_lat_parms [mesons.c]",
                 "Specified nnoise must be larger than zero");

      noisetype=-1;
      if(strcmp(tmpstring,"Z2")==0)
         noisetype=Z2_NOISE;
      if(strcmp(tmpstring,"GAUSS")==0)
         noisetype=GAUSS_NOISE;
      if(strcmp(tmpstring,"U1")==0)
         noisetype=U1_NOISE;
      error_root(noisetype==-1,1,"read_lat_parms [mesons.c]",
                 "Unknown noise type");
   }
   MPI_Bcast(&nprop,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&ncorr,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&nnoise,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&noisetype,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&csw,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(&cF,1,MPI_DOUBLE,0,MPI_COMM_WORLD);

   kappas=malloc(nprop*sizeof(double));
   mus=malloc(nprop*sizeof(double));
   isps=malloc(nprop*sizeof(int));
   props1=malloc(ncorr*sizeof(int));
   props2=malloc(ncorr*sizeof(int));
   type1=malloc(ncorr*sizeof(int));
   type2=malloc(ncorr*sizeof(int));
   x0s=malloc(ncorr*sizeof(int));
   file_head.kappa1=malloc(ncorr*sizeof(double));
   file_head.kappa2=malloc(ncorr*sizeof(double));
   file_head.type1=type1;
   file_head.type2=type2;
   file_head.x0=x0s;
   file_head.isreal=malloc(ncorr*sizeof(int));

   error((kappas==NULL)||(mus==NULL)||(isps==NULL)||(props1==NULL)||
         (props2==NULL)||(type1==NULL)||(type2==NULL)||(x0s==NULL)||
         (file_head.kappa1==NULL)||(file_head.kappa2==NULL)||
         (file_head.isreal==NULL),
         1,"read_lat_parms [mesons.c]","Out of memory");

   if (my_rank==0)
   {
      for(iprop=0; iprop<nprop; iprop++)
      {
         sprintf(tmpstring,"Propagator %i",iprop);
         find_section(tmpstring);
         read_line("kappa","%lf",&kappas[iprop]);
         read_line("isp","%d",&isps[iprop]);
         /*TODO: read optional mu value*/
         mus[iprop]=0;
      }
      for(icorr=0; icorr<ncorr; icorr++)
      {
         sprintf(tmpstring,"Correlator %i",icorr);
         find_section(tmpstring);

         read_line("iprop","%d %d",&props1[icorr],&props2[icorr]);
         error_root((props1[icorr]<0)||(props1[icorr]>=nprop),1,"read_lat_parms [mesons.c]",
                 "Propagator index out of range");
         error_root((props2[icorr]<0)||(props2[icorr]>=nprop),1,"read_lat_parms [mesons.c]",
                 "Propagator index out of range");

         read_line("type","%s %s",tmpstring,tmpstring2);
         type1[icorr]=-1;
         type2[icorr]=-1;
         
         if(strncmp(tmpstring,"1",1)==0)
            type1[icorr]=ONE_TYPE;
         else if(strncmp(tmpstring,"G0G1",4)==0)
            type1[icorr]=GAMMA0GAMMA1_TYPE;
         else if(strncmp(tmpstring,"G0G2",4)==0)
            type1[icorr]=GAMMA0GAMMA2_TYPE;
         else if(strncmp(tmpstring,"G0G3",4)==0)
            type1[icorr]=GAMMA0GAMMA3_TYPE;
         else if(strncmp(tmpstring,"G0G5",4)==0)
            type1[icorr]=GAMMA0GAMMA5_TYPE;
         else if(strncmp(tmpstring,"G1G2",4)==0)
            type1[icorr]=GAMMA1GAMMA2_TYPE;
         else if(strncmp(tmpstring,"G1G3",4)==0)
            type1[icorr]=GAMMA1GAMMA3_TYPE;
         else if(strncmp(tmpstring,"G1G5",4)==0)
            type1[icorr]=GAMMA1GAMMA5_TYPE;
         else if(strncmp(tmpstring,"G2G3",4)==0)
            type1[icorr]=GAMMA2GAMMA3_TYPE;
         else if(strncmp(tmpstring,"G2G5",4)==0)
            type1[icorr]=GAMMA2GAMMA5_TYPE;
         else if(strncmp(tmpstring,"G3G5",4)==0)
            type1[icorr]=GAMMA3GAMMA5_TYPE;
         else if(strncmp(tmpstring,"G0",2)==0)
            type1[icorr]=GAMMA0_TYPE;
         else if(strncmp(tmpstring,"G1",2)==0)
            type1[icorr]=GAMMA1_TYPE;
         else if(strncmp(tmpstring,"G2",2)==0)
            type1[icorr]=GAMMA2_TYPE;
         else if(strncmp(tmpstring,"G3",2)==0)
            type1[icorr]=GAMMA3_TYPE;
         else if(strncmp(tmpstring,"G5",2)==0)
            type1[icorr]=GAMMA5_TYPE;
         
         if(strncmp(tmpstring2,"1",1)==0)
            type2[icorr]=ONE_TYPE;
         else if(strncmp(tmpstring2,"G0G1",4)==0)
            type2[icorr]=GAMMA0GAMMA1_TYPE;
         else if(strncmp(tmpstring2,"G0G2",4)==0)
            type2[icorr]=GAMMA0GAMMA2_TYPE;
         else if(strncmp(tmpstring2,"G0G3",4)==0)
            type2[icorr]=GAMMA0GAMMA3_TYPE;
         else if(strncmp(tmpstring2,"G0G5",4)==0)
            type2[icorr]=GAMMA0GAMMA5_TYPE;
         else if(strncmp(tmpstring2,"G1G2",4)==0)
            type2[icorr]=GAMMA1GAMMA2_TYPE;
         else if(strncmp(tmpstring2,"G1G3",4)==0)
            type2[icorr]=GAMMA1GAMMA3_TYPE;
         else if(strncmp(tmpstring2,"G1G5",4)==0)
            type2[icorr]=GAMMA1GAMMA5_TYPE;
         else if(strncmp(tmpstring2,"G2G3",4)==0)
            type2[icorr]=GAMMA2GAMMA3_TYPE;
         else if(strncmp(tmpstring2,"G2G5",4)==0)
            type2[icorr]=GAMMA2GAMMA5_TYPE;
         else if(strncmp(tmpstring2,"G3G5",4)==0)
            type2[icorr]=GAMMA3GAMMA5_TYPE;
         else if(strncmp(tmpstring2,"G0",2)==0)
            type2[icorr]=GAMMA0_TYPE;
         else if(strncmp(tmpstring2,"G1",2)==0)
            type2[icorr]=GAMMA1_TYPE;
         else if(strncmp(tmpstring2,"G2",2)==0)
            type2[icorr]=GAMMA2_TYPE;
         else if(strncmp(tmpstring2,"G3",2)==0)
            type2[icorr]=GAMMA3_TYPE;
         else if(strncmp(tmpstring2,"G5",2)==0)
            type2[icorr]=GAMMA5_TYPE;

         error_root((type1[icorr]==-1)||(type2[icorr]==-1),1,"read_lat_parms [mesons.c]",
                 "Unknown or unsupported Dirac structure");

         read_line("x0","%d",&x0s[icorr]);
         error_root((x0s[icorr]<=0)||(x0s[icorr]>=(NPROC0*L0-1)),1,"read_lat_parms [mesons.c]",
                 "Specified time x0 is out of range");
      }
   }

   MPI_Bcast(kappas,nprop,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(mus,nprop,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(&csw,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(&cF,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(isps,nprop,MPI_INT,0,MPI_COMM_WORLD);

   MPI_Bcast(props1,ncorr,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(props2,ncorr,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(type1,ncorr,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(type2,ncorr,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(x0s,ncorr,MPI_INT,0,MPI_COMM_WORLD);

   set_lat_parms(0.0,1.0,kappas[0],0.0,0.0,csw,1.0,cF);
   set_sw_parms(sea_quark_mass(0));

   file_head.ncorr = ncorr;
   file_head.nnoise = nnoise;
   file_head.tvals = NPROC0*L0;
   tvals = NPROC0*L0;
   file_head.noisetype = noisetype;
   for(icorr=0; icorr<ncorr; icorr++)
   {
      file_head.kappa1[icorr]=kappas[props1[icorr]];
      file_head.kappa2[icorr]=kappas[props2[icorr]];
      if ((type1[icorr]==GAMMA5_TYPE)&&(type2[icorr]==GAMMA5_TYPE)&&
          (props1[icorr]==props2[icorr]))
         file_head.isreal[icorr]=1;
      else
         file_head.isreal[icorr]=0;
   }
   if (append)
      check_lat_parms(fdat);
   else
      write_lat_parms(fdat);
}


static void read_sap_parms(void)
{
   int bs[4];

   if (my_rank==0)
   {
      find_section("SAP");
      read_line("bs","%d %d %d %d",bs,bs+1,bs+2,bs+3);
   }

   MPI_Bcast(bs,4,MPI_INT,0,MPI_COMM_WORLD);
   set_sap_parms(bs,1,4,5);
}


static void read_dfl_parms(void)
{
   int bs[4],Ns;
   int ninv,nmr,ncy,nkv,nmx;
   double kappa,mudfl,res;

   if (my_rank==0)
   {
      find_section("Deflation subspace");
      read_line("bs","%d %d %d %d",bs,bs+1,bs+2,bs+3);
      read_line("Ns","%d",&Ns);
   }

   MPI_Bcast(bs,4,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&Ns,1,MPI_INT,0,MPI_COMM_WORLD);
   set_dfl_parms(bs,Ns);

   if (my_rank==0)
   {
      find_section("Deflation subspace generation");
      read_line("kappa","%lf",&kappa);
      read_line("mu","%lf",&mudfl);
      read_line("ninv","%d",&ninv);
      read_line("nmr","%d",&nmr);
      read_line("ncy","%d",&ncy);
   }

   MPI_Bcast(&kappa,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(&mudfl,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   MPI_Bcast(&ninv,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&nmr,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&ncy,1,MPI_INT,0,MPI_COMM_WORLD);
   set_dfl_gen_parms(kappa,mudfl,ninv,nmr,ncy);

   if (my_rank==0)
   {
      find_section("Deflation projection");
      read_line("nkv","%d",&nkv);
      read_line("nmx","%d",&nmx);
      read_line("res","%lf",&res);
   }

   MPI_Bcast(&nkv,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&nmx,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&res,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
   set_dfl_pro_parms(nkv,nmx,res);
}


static void read_solvers(void)
{
   solver_parms_t sp;
   int i,j;
   int isap=0,idfl=0;

   for (i=0;i<nprop;i++)
   {
      j=isps[i];
      sp=solver_parms(j);
      if (sp.solver==SOLVERS)
      {
         read_solver_parms(j);
         sp=solver_parms(j);
         if (sp.solver==SAP_GCR)
            isap=1;
         if (sp.solver==DFL_SAP_GCR)
         {
            isap=1;
            idfl=1;
         }
      }
   }

   if (isap)
      read_sap_parms();

   if (idfl)
      read_dfl_parms();
}


static void read_infile(int argc,char *argv[])
{
   int ifile;

   if (my_rank==0)
   {
      flog=freopen("STARTUP_ERROR","w",stdout);
 
      ifile=find_opt(argc,argv,"-i");
      endian=endianness();

      error_root((ifile==0)||(ifile==(argc-1)),1,"read_infile [mesons.c]",
                 "Syntax: mesons -i <input file> [-noexp] [-a [-norng]]");

      error_root(endian==UNKNOWN_ENDIAN,1,"read_infile [mesons.c]",
                 "Machine has unknown endianness");

      noexp=find_opt(argc,argv,"-noexp");
      append=find_opt(argc,argv,"-a");
      norng=find_opt(argc,argv,"-norng");

      fin=freopen(argv[ifile+1],"r",stdin);
      error_root(fin==NULL,1,"read_infile [mesons.c]",
                 "Unable to open input file");
   }

   MPI_Bcast(&endian,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&noexp,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&append,1,MPI_INT,0,MPI_COMM_WORLD);
   MPI_Bcast(&norng,1,MPI_INT,0,MPI_COMM_WORLD);

   read_dirs();
   setup_files();

   if (my_rank==0)
   {
      if (append)
         fdat=fopen(par_file,"rb");
      else
         fdat=fopen(par_file,"wb");

      error_root(fdat==NULL,1,"read_infile [mesons.c]",
                 "Unable to open parameter file");
   }
   read_lat_parms();
   read_solvers();

   if (my_rank==0)
   {
      fclose(fin);
      fclose(fdat);

      if (append==0)
         copy_file(par_file,par_save);
   }
}


static void check_old_log(int *fst,int *lst,int *stp)
{
   int ie,ic,isv;
   int fc,lc,dc,pc;
   int np[4],bp[4];

   fend=fopen(log_file,"r");
   error_root(fend==NULL,1,"check_old_log [mesons.c]",
              "Unable to open log file");

   fc=0;
   lc=0;
   dc=0;
   pc=0;

   ie=0x0;
   ic=0;
   isv=0;

   while (fgets(line,NAME_SIZE,fend)!=NULL)
   {
      if (strstr(line,"process grid")!=NULL)
      {
         if (sscanf(line,"%dx%dx%dx%d process grid, %dx%dx%dx%d",
                    np,np+1,np+2,np+3,bp,bp+1,bp+2,bp+3)==8)
         {
            ipgrd[0]=((np[0]!=NPROC0)||(np[1]!=NPROC1)||
                      (np[2]!=NPROC2)||(np[3]!=NPROC3));
            ipgrd[1]=((bp[0]!=NPROC0_BLK)||(bp[1]!=NPROC1_BLK)||
                      (bp[2]!=NPROC2_BLK)||(bp[3]!=NPROC3_BLK));
         }
         else
            ie|=0x1;
      }
      
      if (strstr(line,"fully processed")!=NULL)
      {
         pc=lc;

         if (sscanf(line,"Configuration no %d",&lc)==1)
         {
            ic+=1;
            isv=1;
         }
         else
            ie|=0x1;

         if (ic==1)
            fc=lc;
         else if (ic==2)
            dc=lc-fc;
         else if ((ic>2)&&(lc!=(pc+dc)))
            ie|=0x2;
      }
      else if (strstr(line,"Configuration no")!=NULL)
         isv=0;
   }

   fclose(fend);

   error_root((ie&0x1)!=0x0,1,"check_old_log [mesons.c]",
              "Incorrect read count");
   error_root((ie&0x2)!=0x0,1,"check_old_log [mesons.c]",
              "Configuration numbers are not equally spaced");
   error_root(isv==0,1,"check_old_log [mesons.c]",
              "Log file extends beyond the last configuration save");

   (*fst)=fc;
   (*lst)=lc;
   (*stp)=dc;
}


static void check_old_dat(int fst,int lst,int stp)
{
   int ie,ic;
   int fc,lc,dc,pc;

   fdat=fopen(dat_file,"rb");
   error_root(fdat==NULL,1,"check_old_dat [mesons.c]",
              "Unable to open data file");

   check_file_head();

   fc=0;
   ic=0;
   lc=0;
   dc=0;
   pc=0;
   ie=0x0;

   while (read_data()==1)
   {
      pc=lc;
      lc=data.nc;
      ic+=1;

      if (ic==1)
         fc=lc;
      else if (ic==2)
         dc=lc-fc;
      else if ((ic>2)&&(lc!=(pc+dc)))
         ie|=0x1;
   }

   fclose(fdat);

   error_root(ic==0,1,"check_old_dat [mesons.c]",
              "No data records found");
   error_root((ie&0x1)!=0x0,1,"check_old_dat [mesons.c]",
              "Configuration numbers are not equally spaced");
   error_root((fst!=fc)||(lst!=lc)||(stp!=dc),1,"check_old_dat [mesons.c]",
              "Configuration range is not as reported in the log file");
}


static void check_files(void)
{
   int fst,lst,stp;

   ipgrd[0]=0;
   ipgrd[1]=0;
   
   if (my_rank==0)
   {
      if (append)
      {
         check_old_log(&fst,&lst,&stp);
         check_old_dat(fst,lst,stp);

         error_root((fst!=lst)&&(stp!=step),1,"check_files [mesons.c]",
                    "Continuation run:\n"
                    "Previous run had a different configuration separation");
         error_root(first!=lst+step,1,"check_files [mesons.c]",
                    "Continuation run:\n"
                    "Configuration range does not continue the previous one");
      }
      else
      {
         fin=fopen(log_file,"r");
         error_root(fin!=NULL,1,"check_files [mesons.c]",
                    "Attempt to overwrite old *.log file");
         fdat=fopen(dat_file,"r");
         error_root(fdat!=NULL,1,"check_files [mesons.c]",
                    "Attempt to overwrite old *.dat file");
         fdat=fopen(dat_file,"wb");
         error_root(fdat==NULL,1,"check_files [mesons.c]",
                    "Unable to open data file");
         write_file_head();
         fclose(fdat);
      }
   }
}


static void print_info(void)
{
   int i,isap,idfl;
   long ip;
   lat_parms_t lat;

   if (my_rank==0)
   {
      ip=ftell(flog);
      fclose(flog);

      if (ip==0L)
         remove("STARTUP_ERROR");

      if (append)
         flog=freopen(log_file,"a",stdout);
      else
         flog=freopen(log_file,"w",stdout);

      error_root(flog==NULL,1,"print_info [mesons.c]",
                 "Unable to open log file");
      printf("\n");

      if (append)
         printf("Continuation run\n\n");
      else
      {
         printf("Computation of meson correlators\n");
         printf("--------------------------------\n\n");
         printf("cnfg   base name: %s\n",nbase);
         printf("output base name: %s\n\n",outbase);
      }

      printf("openQCD version: %s, meson version: %s\n",openQCD_RELEASE,
                                                      mesons_RELEASE);
      if (endian==LITTLE_ENDIAN)
         printf("The machine is little endian\n");
      else
         printf("The machine is big endian\n");
      if (noexp)
         printf("Configurations are read in imported file format\n\n");
      else
         printf("Configurations are read in exported file format\n\n");

      if ((ipgrd[0]!=0)&&(ipgrd[1]!=0))
         printf("Process grid and process block size changed:\n");
      else if (ipgrd[0]!=0)
         printf("Process grid changed:\n");
      else if (ipgrd[1]!=0)
         printf("Process block size changed:\n");

      if ((append==0)||(ipgrd[0]!=0)||(ipgrd[1]!=0))
      {
         printf("%dx%dx%dx%d lattice, ",N0,N1,N2,N3);
         printf("%dx%dx%dx%d local lattice\n",L0,L1,L2,L3);
         printf("%dx%dx%dx%d process grid, ",NPROC0,NPROC1,NPROC2,NPROC3);
         printf("%dx%dx%dx%d process block size\n",
                NPROC0_BLK,NPROC1_BLK,NPROC2_BLK,NPROC3_BLK);

         if (append)
            printf("\n");
         else
            printf("SF boundary conditions on the quark fields\n\n");
      }
      
      
      if (append)
      {
         printf("Random number generator:\n");

         if (norng)
            printf("level = %d, seed = %d, effective seed = %d\n\n",
                   level,seed,seed^(first-step));
         else
         {
            printf("State of ranlxs and ranlxd reset to the\n");
            printf("last exported state\n\n");
         }
      }
      else
      {
         printf("Random number generator:\n");
         printf("level = %d, seed = %d\n\n",level,seed);

         lat=lat_parms();

         printf("Measurements:\n");
         printf("nprop     = %i\n",nprop);
         printf("ncorr     = %i\n",ncorr);
         printf("nnoise    = %i\n",nnoise);
         if (noisetype==Z2_NOISE)
            printf("noisetype = Z2\n");
         if (noisetype==GAUSS_NOISE)
            printf("noisetype = GAUSS\n");
         if (noisetype==U1_NOISE)
            printf("noisetype = U1\n");
         printf("csw       = %.6f\n",lat.csw);
         printf("cF        = %.6f\n\n",lat.cF);

         for (i=0; i<nprop; i++)
         {
            printf("Propagator %i:\n",i);
            printf("kappa  = %.6f\n",kappas[i]);
            printf("isp    = %i\n",isps[i]);
            printf("mu     = %.6f\n\n",mus[i]);
         }
         for (i=0; i<ncorr; i++)
         {
            printf("Correlator %i:\n",i);
            printf("iprop  = %i %i\n",props1[i],props2[i]);
            printf("type   = %i %i\n",type1[i],type2[i]); /*TODO: strings*/
            printf("x0     = %i\n\n",x0s[i]);
         }
      }
      print_solver_parms(&isap,&idfl);

      if (isap)
         print_sap_parms(0);

      if (idfl)
         print_dfl_parms(0);

      printf("Configurations no %d -> %d in steps of %d\n\n",
             first,last,step);
      fflush(flog);
   }
}


static void dfl_wsize(int *nws,int *nwv,int *nwvd)
{
   dfl_parms_t dp;
   dfl_pro_parms_t dpp;

   dp=dfl_parms();
   dpp=dfl_pro_parms();

   MAX(*nws,dp.Ns+2);
   MAX(*nwv,2*dpp.nkv+2);
   MAX(*nwvd,4);
}


static void make_proplist(void)
{
   int i,j,k,iprop,icorr;
   char *kappatype;

   proplist.nux0=0;
   proplist.ux0=malloc(NPROC0*L0*sizeof(int));
   error(proplist.ux0==NULL,1,"make_proplist [mesons.c]","Out of memory");

   /* unique x0 values */
   for (icorr=0;icorr<ncorr;icorr++)
   {
      for (j=0;j<proplist.nux0;j++)
      {
         if (proplist.ux0[j]==x0s[icorr])
            break;
      }
      if (j==proplist.nux0)
      {
         proplist.ux0[j]=x0s[icorr];
         proplist.nux0++;
      }
   }

   proplist.nprop=malloc(proplist.nux0*sizeof(int));
   proplist.prop=malloc(proplist.nux0*sizeof(int*));
   proplist.type=malloc(proplist.nux0*sizeof(int*));
   kappatype=malloc(MAX_TYPE*nprop*sizeof(char));
   error((proplist.nprop==NULL)||(proplist.prop==NULL)||(proplist.type==NULL)
               ||(kappatype==NULL),
               1,"make_proplist [mesons.c]","Out of memory");
   proplist.nmax=0;

   for (i=0;i<proplist.nux0;i++)
   {
      for (j=0;j<MAX_TYPE*nprop;j++)
         kappatype[j]=0;

      proplist.nprop[i]=0;
      for (icorr=0;icorr<ncorr;icorr++)
      {
         if (x0s[icorr]==proplist.ux0[i])
         {
            if (!kappatype[type1[icorr]+MAX_TYPE*props2[icorr]])
            {
               kappatype[type1[icorr]+MAX_TYPE*props2[icorr]]=1;
               proplist.nprop[i]++;
            }
            if (!kappatype[GAMMA5_TYPE+MAX_TYPE*props1[icorr]])
            {
               kappatype[GAMMA5_TYPE+MAX_TYPE*props1[icorr]]=1;
               proplist.nprop[i]++;
            }
         }
      }

      if (proplist.nprop[i]>proplist.nmax)
         proplist.nmax=proplist.nprop[i];

      proplist.prop[i]=malloc(proplist.nprop[i]*sizeof(int));
      proplist.type[i]=malloc(proplist.nprop[i]*sizeof(int));
      error((proplist.prop[i]==NULL)||(proplist.type[i]==NULL),
                 1,"make_proplist [mesons.c]","Out of memory");
      j=0;
      for (k=0;k<MAX_TYPE;k++)
      {
         for (iprop=0;iprop<nprop;iprop++)
         {
            if (kappatype[k+MAX_TYPE*iprop])
            {
               proplist.prop[i][j]=iprop;
               proplist.type[i][j]=k;
               j++;
            }
         }
      }
   }
   free(kappatype);
}

static void wsize(int *nws,int *nwsd,int *nwv,int *nwvd)
{
   int nsd;
   solver_parms_t sp;

   (*nws)=0;
   (*nwsd)=0;
   (*nwv)=0;
   (*nwvd)=0;

   sp=solver_parms(0);
   nsd=proplist.nmax+2;

   if (sp.solver==CGNE)
   {
      MAX(*nws,5);
      MAX(*nwsd,nsd+3);
   }
   else if (sp.solver==SAP_GCR)
   {
      MAX(*nws,2*sp.nkv+1);
      MAX(*nwsd,nsd+2);
   }
   else if (sp.solver==DFL_SAP_GCR)
   {
      MAX(*nws,2*sp.nkv+2);
      MAX(*nwsd,nsd+4);
      dfl_wsize(nws,nwv,nwvd);
   }
   else
      error_root(1,1,"wsize [mesons.c]",
                 "Unknown or unsupported solver");
}



static void random_source(spinor_dble *eta, int x0)
{
   int y0,iy,ix;

   set_sd2zero(VOLUME,eta);
   y0=x0-cpr[0]*L0;

   if ((y0>=0)&&(y0<L0))
   {
      if (noisetype==Z2_NOISE)
      {
         for (iy=0;iy<(L1*L2*L3);iy++)
         {
            ix=ipt[iy+y0*L1*L2*L3];
            random_Z2_sd(1,eta+ix);
         }
      }
      else if (noisetype==GAUSS_NOISE)
      {
         for (iy=0;iy<(L1*L2*L3);iy++)
         {
            ix=ipt[iy+y0*L1*L2*L3];
            random_sd(1,eta+ix,1.0);
         }
      }
      else if (noisetype==U1_NOISE)
      {
         for (iy=0;iy<(L1*L2*L3);iy++)
         {
            ix=ipt[iy+y0*L1*L2*L3];
            random_U1_sd(1,eta+ix);
         }
      }
   }
}


static void solve_dirac(int prop, spinor_dble *eta, spinor_dble *psi,
                        int *status)
{
   solver_parms_t sp;
   sap_parms_t sap;

   sp=solver_parms(isps[prop]);
   set_sw_parms(0.5/kappas[prop]-4.0);

   if (sp.solver==CGNE)
   {
      mulg5_dble(VOLUME,eta);

      tmcg(sp.nmx,sp.res,mus[prop],eta,eta,status);
      if (my_rank==0)
         printf("%i\n",status[0]);
      error_root(status[0]<0,1,"solve_dirac [mesons.c]",
                 "CGNE solver failed (status = %d)",status[0]);

      Dw_dble(-mus[prop],eta,psi);
      mulg5_dble(VOLUME,psi);
   }
   else if (sp.solver==SAP_GCR)
   {
      sap=sap_parms();
      set_sap_parms(sap.bs,sp.isolv,sp.nmr,sp.ncy);

      sap_gcr(sp.nkv,sp.nmx,sp.res,mus[prop],eta,psi,status);
      if (my_rank==0)
         printf("%i\n",status[0]);
      error_root(status[0]<0,1,"solve_dirac [mesons.c]",
                 "SAP_GCR solver failed (status = %d)",status[0]);
   }
   else if (sp.solver==DFL_SAP_GCR)
   {
      sap=sap_parms();
      set_sap_parms(sap.bs,sp.isolv,sp.nmr,sp.ncy);

      dfl_sap_gcr2(sp.nkv,sp.nmx,sp.res,mus[prop],eta,psi,status);
      if (my_rank==0)
         printf("%i %i\n",status[0],status[1]);
      error_root((status[0]<0)||(status[1]<0),1,
                 "solve_dirac [mesons.c]","DFL_SAP_GCR solver failed "
                 "(status = %d,%d)",status[0],status[1]);
   }
   else
      error_root(1,1,"solve_dirac [mesons.c]",
                 "Unknown or unsupported solver");
}


/* xi = \gamma_5 Gamma^\dagger eta */
void make_source(spinor_dble *eta, int type, spinor_dble *xi)
{
   switch (type)
   {
      case GAMMA0_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg0g5_dble(VOLUME,xi);
         break;
      case GAMMA1_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg1g5_dble(VOLUME,xi);
         break;
      case GAMMA2_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg2g5_dble(VOLUME,xi);
         break;
      case GAMMA3_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg3g5_dble(VOLUME,xi);
         break;
      case GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         break;
      case GAMMA0GAMMA1_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg2g3_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA2_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg1g3_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA3_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg1g2_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA2_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0g3_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA3_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg0g2_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg1_dble(VOLUME,xi);
         break;
      case GAMMA2GAMMA3_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0g1_dble(VOLUME,xi);
         break;
      case GAMMA2GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg2_dble(VOLUME,xi);
         break;
      case GAMMA3GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg3_dble(VOLUME,xi);
         break;
      case ONE_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg5_dble(VOLUME,xi);
         break;
      default:
         error_root(1,1,"make_source [mesons.c]",
                 "Unknown or unsupported type");
   }
}

void make_xi(spinor_dble *eta,int type,spinor_dble *xi)
{
   /* xi = -\bar Gamma^\dagger \gamma_5 eta */
   switch (type)
   {
      case GAMMA0_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg0g5_dble(VOLUME,xi);
         break;
      case GAMMA1_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg1g5_dble(VOLUME,xi);
         break;
      case GAMMA2_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg2g5_dble(VOLUME,xi);
         break;
      case GAMMA3_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg3g5_dble(VOLUME,xi);
         break;
      case GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         break;
      case GAMMA0GAMMA1_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg2g3_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA2_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg1g3_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA3_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg1g2_dble(VOLUME,xi);
         break;
      case GAMMA0GAMMA5_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA2_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0g3_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA3_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg0g2_dble(VOLUME,xi);
         break;
      case GAMMA1GAMMA5_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg1_dble(VOLUME,xi);
         break;
      case GAMMA2GAMMA3_TYPE:
         assign_sd2sd(VOLUME,eta,xi);
         mulg0g1_dble(VOLUME,xi);
         break;
      case GAMMA2GAMMA5_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg2_dble(VOLUME,xi);
         break;
      case GAMMA3GAMMA5_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg3_dble(VOLUME,xi);
         break;
      case ONE_TYPE:
         assign_msd2sd(VOLUME,eta,xi);
         mulg5_dble(VOLUME,xi);
         break;
      default:
         error_root(1,1,"make_xi [mesons.c]",
                 "Unknown or unsupported type");
   }
}


static void correlators(void)
{
   int ix0,inoise,iprop,icorr,ip1,ip2,l,stat[4],y0,iy;
   spinor_dble *eta,*xi,**zeta,**wsd;
   complex_dble tmp;

   wsd=reserve_wsd(proplist.nmax+2);
   eta=wsd[0];
   xi=wsd[1];
   zeta=malloc(proplist.nmax*sizeof(spinor_dble*));
   error(zeta==NULL,1,"correlators [mesons.c]","Out of memory");

   for (l=0;l<proplist.nmax;l++)
      zeta[l]=wsd[l+2];

   for (l=0;l<nnoise*ncorr*tvals;l++)
   {
      data.corr_tmp[l].re=0.0;
      data.corr_tmp[l].im=0.0;
   }

   if (my_rank==0)
      printf("Inversions:\n");
   for (ix0=0;ix0<proplist.nux0;ix0++)
   {
      if (my_rank==0)
         printf("   x0=%i\n",proplist.ux0[ix0]);
      for (inoise=0;inoise<nnoise;inoise++)
      {
         if (my_rank==0)
            printf("      noise vector %i\n",inoise);
         random_source(eta,proplist.ux0[ix0]);
         for (iprop=0;iprop<proplist.nprop[ix0];iprop++)
         {
            if (my_rank==0)
               printf("         type=%i, prop=%i, status:",
                   proplist.type[ix0][iprop], proplist.prop[ix0][iprop]);
            make_source(eta,proplist.type[ix0][iprop],xi);
            solve_dirac(proplist.prop[ix0][iprop],xi,zeta[iprop],stat);
         }
         /* combine propagators to correlators */
         for (icorr=0;icorr<ncorr;icorr++)
         {
            if (x0s[icorr]==proplist.ux0[ix0])
            {
               /* find the two propagators that are needed for this icorr */
               ip1=0;
               ip2=0;
               for (iprop=0;iprop<proplist.nprop[ix0];iprop++)
               {
                  if ((type1[icorr]==proplist.type[ix0][iprop])&&
                      (props2[icorr]==proplist.prop[ix0][iprop]))
                     ip1=iprop;
                  if ((GAMMA5_TYPE==proplist.type[ix0][iprop])&&
                      (props1[icorr]==proplist.prop[ix0][iprop]))
                     ip2=iprop;
               }
               make_xi(zeta[ip1],type2[icorr],xi);
               for (y0=0;y0<L0;y0++)
               {
                  for (l=0;l<L1*L2*L3;l++)
                  {
                     iy = ipt[l+y0*L1*L2*L3];
                     tmp = spinor_prod_dble(1,0,xi+iy,zeta[ip2]+iy);
                     data.corr_tmp[inoise+nnoise*(cpr[0]*L0+y0
                        +file_head.tvals*icorr)].re += tmp.re;
                     data.corr_tmp[inoise+nnoise*(cpr[0]*L0+y0
                        +file_head.tvals*icorr)].im += tmp.im;
                  }
               }
            }
         }
      }
   }

   MPI_Allreduce(data.corr_tmp,data.corr,nnoise*ncorr*file_head.tvals*2
      ,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
   free(zeta);
   release_wsd();
}

static void set_data(int nc)
{
   data.nc=nc;
   correlators();

   if (my_rank==0)
   {
      printf("G(t) =  %.4e%+.4ei",data.corr[0].re,data.corr[0].im);
      printf(",%.4e%+.4ei,...",data.corr[1].re,data.corr[1].im);
      printf(",%.4e%+.4ei",data.corr[file_head.tvals-1].re,
                           data.corr[file_head.tvals-1].im);
      printf("\n");
      fflush(flog);
   }
}

static void init_rng(void)
{
   int ic;

   if (append)
   {
      if (norng)
         start_ranlux(level,seed^(first-step));
      else
      {
         ic=import_ranlux(rng_file);
         error_root(ic!=(first-step),1,"init_rng [mesons.c]",
                    "Configuration number mismatch (*.rng file)");
      }
   }
   else
      start_ranlux(level,seed);
}


static void save_ranlux(void)
{
   int nlxs,nlxd;

   if (rlxs_state==NULL)
   {
      nlxs=rlxs_size();
      nlxd=rlxd_size();

      rlxs_state=malloc((nlxs+nlxd)*sizeof(int));
      rlxd_state=rlxs_state+nlxs;

      error(rlxs_state==NULL,1,"save_ranlux [mesons.c]",
            "Unable to allocate state arrays");
   }

   rlxs_get(rlxs_state);
   rlxd_get(rlxd_state);
}


static void restore_ranlux(void)
{
   rlxs_reset(rlxs_state);
   rlxd_reset(rlxd_state);
}


static void check_endflag(int *iend)
{
   if (my_rank==0)
   {
      fend=fopen(end_file,"r");

      if (fend!=NULL)
      {
         fclose(fend);
         remove(end_file);
         (*iend)=1;
         printf("End flag set, run stopped\n\n");
      }
      else
         (*iend)=0;
   }

   MPI_Bcast(iend,1,MPI_INT,0,MPI_COMM_WORLD);
}


int main(int argc,char *argv[])
{
   int nc,iend,status[4];
   int nws,nwsd,nwv,nwvd;
   double wt1,wt2,wtavg;
   dfl_parms_t dfl;

   MPI_Init(&argc,&argv);
   MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);

   read_infile(argc,argv);
   alloc_data();
   check_files();
   print_info();
   dfl=dfl_parms();

   geometry();
   init_rng();

   make_proplist();
   wsize(&nws,&nwsd,&nwv,&nwvd);
   alloc_ws(nws);
   alloc_wsd(nwsd);
   alloc_wv(nwv);
   alloc_wvd(nwvd);

   iend=0;
   wtavg=0.0;

   for (nc=first;(iend==0)&&(nc<=last);nc+=step)
   {
      MPI_Barrier(MPI_COMM_WORLD);
      wt1=MPI_Wtime();

      if (my_rank==0)
         printf("Configuration no %d\n",nc);

      if (noexp)
      {
         save_ranlux();
         sprintf(cnfg_file,"%s/%sn%d_%d",loc_dir,nbase,nc,my_rank);
         read_cnfg(cnfg_file);
         restore_ranlux();
      }
      else
      {
         sprintf(cnfg_file,"%s/%sn%d",cnfg_dir,nbase,nc);
         import_cnfg(cnfg_file);
      }

      if (dfl.Ns)
      {
         dfl_modes(status);
         error_root(status[0]<0,1,"main [mesons.c]",
                    "Deflation subspace generation failed (status = %d)",
                    status[0]);

         if (my_rank==0)
            printf("Deflation subspace generation: status = %d\n",status[0]);
      }

      set_data(nc);
      write_data();

      export_ranlux(nc,rng_file);
      error_chk();
      
      MPI_Barrier(MPI_COMM_WORLD);
      wt2=MPI_Wtime();
      wtavg+=(wt2-wt1);
      

      if (my_rank==0)
      {
         printf("Configuration no %d fully processed in %.2e sec ",
                nc,wt2-wt1);
         printf("(average = %.2e sec)\n\n",
                wtavg/(double)((nc-first)/step+1));
      }
      check_endflag(&iend);

      if (my_rank==0)
      {
         fflush(flog);
         copy_file(log_file,log_save);
         copy_file(dat_file,dat_save);
         copy_file(rng_file,rng_save);
      }
   }


   if (my_rank==0)
   {
      fclose(flog);
   }

   MPI_Finalize();
   exit(0);
}
back to top