 /*****************************************************

  Copyright (C) 2011, 2012 Andrea Nobile

  

*******************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mpi.h"
#include "su3.h"
#include "random.h"
#include "start.h"
#include "misc.h"
#include "update.h"
#include "linalg.h"
#include "block.h"
#include "sw_term.h"
#include "dirac.h"
#include "sap_gcr.h"
#include "global.h"
#include "init.h"
#include "dds_interface.h"


spinor_dble *_dds_src;
spinor_dble *_dds_dst;
spinor_dble *_dds_tmp;

extern int _ndfl;
extern int _blkrel;
extern int _dd_init;

int gauge_updated=0;

void dds_init(dds_lat_grid *par) 
{
  
  
  _dds_init_internal(*par, 1);

}

double *dds_sptr_src(int t, int x, int y, int z)
{
  double *ptr;
  int co[4];
  int ip, idx;
  
  co[0] = t;
  co[1] = x;
  co[2] = y;
  co[3] = z;
  
  ipt_global(co, &ip, &idx);
  ptr = (double*) &_dds_src[idx];
  
  return ptr;
}

double *dds_sptr_dst(int t, int x, int y, int z)
{
  double *ptr;
  int co[4];
  int ip, idx;
  
  co[0] = t;
  co[1] = x;
  co[2] = y;
  co[3] = z;
  
  ipt_global(co, &ip, &idx);
  ptr = (double*) &_dds_dst[idx];
  
  return ptr;

}

double *dds_uptr(int t, int x, int y, int z, int mu)
{
  double *ptr;
  int co[4];
  int ip, idx;
  
  co[0] = t;
  co[1] = x;
  co[2] = y;
  co[3] = z;
  
  ipt_global(co, &ip, &idx);
  ptr = (double*) pud[idx][mu];
  
  return ptr;
}

void dds_clover(double kappa, double csw)
{

  double beta = 5.3;

  set_lat_parms(beta, kappa, csw);
  MPI_Barrier(MPI_COMM_WORLD);
  sw_term();
  MPI_Barrier(MPI_COMM_WORLD);
}


int dds_solve(double kappa, double csw, double tol, int nmx, double *res)
{
  
  int id0,id1;
  double res1;
  int fail, status;
  double beta = 5.3;

  set_lat_parms(beta, kappa, csw);

  id0=(_dds_src-psd[0][0])/NSPIN;
  id1=(_dds_dst-psd[0][0])/NSPIN;
  
  MPI_Barrier(MPI_COMM_WORLD);
  if(_ndfl ==0) {
    res1=sap_gcr(nmx, tol,id0,id1,&status,&fail);
  } else {
    if(_blkrel == 0) {
      res1=sap_fgmres_dr(nmx, _ndfl, tol,id0,id1,&status,&fail);
    }else if(_blkrel==1) {
      res1=ssap_fgmres_dr(nmx, _ndfl, tol,id0,id1,&status,&fail);
    }
    else res1=1.0;
  }
  
  
  MPI_Barrier(MPI_COMM_WORLD);
  
  *res = res1;
  
  return status;

}



void dds_gauge_updated()
{

  gauge_updated=1;
}

void dds_dirac(double kappa, double csw)
{
  
  int id0,id1;
  double beta = 5.3;

  set_lat_parms(beta, kappa, csw);

  id0=(_dds_src-psd[0][0])/NSPIN;
  id1=(_dds_dst-psd[0][0])/NSPIN;
  
  MPI_Barrier(MPI_COMM_WORLD);
  sw_term();
  Qnohat_dble(id0,id1);
  mulg5_dble(VOLUME,_dds_dst);
  //res1=sap_fgmres_dr(nmx, 1, tol,id0,id1,&status,&fail);
  MPI_Barrier(MPI_COMM_WORLD);


}

void dds_tune(int nmr, int ncy, int nkv, int ndfl, int blkrel, int *bs)
{
  
  if(_dd_init) {
    
    _ndfl = ndfl;
    _blkrel = blkrel;
    set_gcr_parms(bs, nmr, ncy, nkv);
  
    if(ndfl == 0) {
      //free_s();
      //alloc_s(2*nkv+3);
      _ndfl = 1;
    }
  } else {

    printf("dds_tune: :( dds not initialized");
    exit(1);

  }
  
}

