
/*******************************************************************************
*
* File Qhat.c
*
* Copyright (C) 2005 Martin Luescher, 2007 Bjoern Leder, 2010 Andrea Nobile
*
* This software is distributed under the terms of the GNU General Public
* License (GPL)
*
* Application of the even-odd preconditioned Wilson-Dirac operator
*
* The externally accessible functions are
*
*   void Qhat(int k,int l)
*     Applies Qhat to the global single-precision field *ps[k][] and assigns
*     the result to *ps[l][]
*
*   void Qoe(int k,int l)
*     Applies the operator Qoe to the even part of the global single-precision
*     field *ps[k][] and assigns the result to *ps[l][]
*
*   void Qeo(int k,int l)
*     Applies the operator Qeo to the odd part of the global single-precision
*     field *ps[k][] and *subtracts* the result from *ps[l][]
*
*   void Qnohat(int k,int l)
*     Applies the full Dirac operator Q to the global single-precision field
*     *ps[k][] and assigns the result to *ps[l][]
*
*   void Qhat_blk(block_t *b,int k,int l)
*     Applies Qhat to the single-precision field b.s[k][] on the block b and
*     assigns the result to b.s[l][]
*
*   void Qoe_blk(block_t *b,int k,int l)
*     Applies the operator Qoe to the even part of the single-precision field
*     b.s[k][] on the block b and assigns the result to b.s[l][]
*
*   void Qeo_blk(block_t *b,int k,int l)
*     Applies the operator Qeo to the odd part of the single-precision field
*     b.s[k][] on the block b and *subtracts* the result from b.s[l][]
*
*   void Qnohat_blk(block_t *b,int k,int l)
*     Applies the full Dirac operator Q to the single-precision field b.s[k][]
*     on the block b and assigns the result to b.s[l][]
*
* Notes:
*
* The notation and normalization conventions are specified in the notes
* "Implementation of the lattice Dirac operator" (file doc/dirac.ps)
*
* In all these programs it is assumed that Qee and Qoo (or 1/Qoo in the
* case of the preconditioned operator) are stored in the appropriate sw
* arrays. Whether the field arrays are in the proper condition can normally
* be determined by querying the flags data base [see flags.c]
*
* All non-block programs in this file act globally and should be called
* from all processes with the same parameters. Communication buffers are
* allocated automatically when needed
*
* The block programs, on the other hand, act locally. Any errors occuring in
* these are recorded by the error_loc [utils.c] function
*
*******************************************************************************/

#define QHAT_C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
//#include "mpi.h"
#include "su3.h"
//#include "flags.h"
//#include "start.h"
//nclude "block.h"
//nclude "sw_term.h"
//nclude "dirac.h"
//nclude "global.h"

static float coe=-0.25,ceo;
static const spinor s0={{{0.0f}}};

#define _vector_mul_assign(r,c) \
   (r).c1.re*=(c); \
   (r).c1.im*=(c); \
   (r).c2.re*=(c); \
   (r).c2.im*=(c); \
   (r).c3.re*=(c); \
   (r).c3.im*=(c)

#if (defined VERBOSE_DEBUG)

#define _print_dir(mu) \
    printf( "\ndir %s\n", mu )

#define _cv_print(a) \
    printf( "vecX = {%f+j%f, %f+j%f, %f+j%f}\n", a.c1.re, a.c1.im, a.c2.re, a.c2.im, a.c3.re, a.c3.im ) 

#define _cv_print2(a,b) \
    printf( "vecA = {%f+j%f, %f+j%f, %f+j%f}\n", a.c1.re, a.c1.im, a.c2.re, a.c2.im, a.c3.re, a.c3.im ); \
    printf( "vecB = {%f+j%f, %f+j%f, %f+j%f}\n", b.c1.re, b.c1.im, b.c2.re, b.c2.im, b.c3.re, b.c3.im ) 

#else

#define _print_dir(mu)
#define _cv_print(a)
#define _cv_print2(a,b)

#endif

//static spinor rs;
spinor rs;


//static void qoe(int *piup,int *pidn,su3 *u,spinor *pk)
void qoe(int *piup,int *pidn,su3 *u,spinor *pk)
{
   spinor *sp,*sm;
   su3_vector psi,chi;

/******************************* direction +0 *********************************/

      sp=pk+(*(piup++));

      _print_dir("+0");
      _cv_print2( (*sp).c1, (*sp).c2 );
      _cv_print2( (*sp).c3, (*sp).c4 );

      _vector_add(psi,(*sp).c1,(*sp).c3);
      _cv_print( psi );
      _su3_multiply(rs.c1,*u,psi);
      rs.c3=rs.c1;

      _vector_add(psi,(*sp).c2,(*sp).c4);
      _cv_print( psi );
      _su3_multiply(rs.c2,*u,psi);
      rs.c4=rs.c2;

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction -0 *********************************/

      sm=pk+(*(pidn++));
      u+=1;

      _print_dir("-0");

      _vector_sub(psi,(*sm).c1,(*sm).c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );

      _vector_add_assign(rs.c1,chi);
      _vector_sub_assign(rs.c3,chi);

      _vector_sub(psi,(*sm).c2,(*sm).c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );

      _vector_add_assign(rs.c2,chi);
      _vector_sub_assign(rs.c4,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction +1 *********************************/

      sp=pk+(*(piup++));
      u+=1;

      _print_dir("+1");

      _vector_i_add(psi,(*sp).c1,(*sp).c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_i_sub_assign(rs.c4,chi);

      _vector_i_add(psi,(*sp).c2,(*sp).c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_i_sub_assign(rs.c3,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction -1 *********************************/

      sm=pk+(*(pidn++));
      u+=1;

      _print_dir("-1");

      _vector_i_sub(psi,(*sm).c1,(*sm).c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_i_add_assign(rs.c4,chi);

      _vector_i_sub(psi,(*sm).c2,(*sm).c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_i_add_assign(rs.c3,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction +2 *********************************/

      sp=pk+(*(piup++));
      u+=1;

      _print_dir("+2");

      _vector_add(psi,(*sp).c1,(*sp).c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_add_assign(rs.c4,chi);

      _vector_sub(psi,(*sp).c2,(*sp).c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_sub_assign(rs.c3,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction -2 *********************************/

      sm=pk+(*(pidn++));
      u+=1;

      _print_dir("-2");

      _vector_sub(psi,(*sm).c1,(*sm).c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_sub_assign(rs.c4,chi);

      _vector_add(psi,(*sm).c2,(*sm).c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_add_assign(rs.c3,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction +3 *********************************/

      sp=pk+(*(piup));
      u+=1;

      _print_dir("+3");

      _vector_i_add(psi,(*sp).c1,(*sp).c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_i_sub_assign(rs.c3,chi);

      _vector_i_sub(psi,(*sp).c2,(*sp).c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_i_add_assign(rs.c4,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

/******************************* direction -3 *********************************/

      sm=pk+(*(pidn));
      u+=1;

      _print_dir("-3");

      _vector_i_sub(psi,(*sm).c1,(*sm).c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c1,chi);
      _vector_i_add_assign(rs.c3,chi);

      _vector_i_add(psi,(*sm).c2,(*sm).c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_add_assign(rs.c2,chi);
      _vector_i_sub_assign(rs.c4,chi);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );

      _vector_mul_assign(rs.c1,-coe);
      _vector_mul_assign(rs.c2,-coe);
      _vector_mul_assign(rs.c3,coe);
      _vector_mul_assign(rs.c4,coe);

      _cv_print2( rs.c1, rs.c2 );
      _cv_print2( rs.c3, rs.c4 );
}


//static void qeo(int *piup,int *pidn,su3 *u,spinor *pl)
void qeo(int *piup,int *pidn,su3 *u,spinor *pl)
{
   spinor *sp,*sm;
   su3_vector psi,chi;

   _cv_print2( rs.c1, rs.c2 );
   _cv_print2( rs.c3, rs.c4 );

/******************************* direction +0 *********************************/

      sp=pl+(*(piup++));

      _print_dir("+0");

      _vector_sub(psi,rs.c1,rs.c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c1,chi);
      _vector_sub_assign((*sp).c3,chi);

      _vector_sub(psi,rs.c2,rs.c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c2,chi);
      _vector_sub_assign((*sp).c4,chi);

      _cv_print2( (*sp).c1, (*sp).c2 );
      _cv_print2( (*sp).c3, (*sp).c4 );

/******************************* direction -0 *********************************/

      sm=pl+(*(pidn++));
      u+=1;

      _print_dir("-0");

      _vector_add(psi,rs.c1,rs.c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );

      _vector_sub_assign((*sm).c1,chi);
      _vector_add_assign((*sm).c3,chi);

      _vector_add(psi,rs.c2,rs.c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );

      _vector_sub_assign((*sm).c2,chi);
      _vector_add_assign((*sm).c4,chi);

      _cv_print2( (*sm).c1, (*sm).c2 );
      _cv_print2( (*sm).c3, (*sm).c4 );

/******************************* direction +1 *********************************/

      sp=pl+(*(piup++));
      u+=1;

      _print_dir("+1");

      _vector_i_sub(psi,rs.c1,rs.c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c1,chi);
      _vector_i_add_assign((*sp).c4,chi);

      _vector_i_sub(psi,rs.c2,rs.c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c2,chi);
      _vector_i_add_assign((*sp).c3,chi);

      _cv_print2( (*sp).c1, (*sp).c2 );
      _cv_print2( (*sp).c3, (*sp).c4 );

/******************************* direction -1 *********************************/

      sm=pl+(*(pidn++));
      u+=1;

      _print_dir("-1");

      _vector_i_add(psi,rs.c1,rs.c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c1,chi);
      _vector_i_sub_assign((*sm).c4,chi);

      _vector_i_add(psi,rs.c2,rs.c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c2,chi);
      _vector_i_sub_assign((*sm).c3,chi);

      _cv_print2( (*sm).c1, (*sm).c2 );
      _cv_print2( (*sm).c3, (*sm).c4 );

/******************************* direction +2 *********************************/

      sp=pl+(*(piup++));
      u+=1;

      _print_dir("+2");

      _vector_sub(psi,rs.c1,rs.c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c1,chi);
      _vector_sub_assign((*sp).c4,chi);

      _vector_add(psi,rs.c2,rs.c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c2,chi);
      _vector_add_assign((*sp).c3,chi);

      _cv_print2( (*sp).c1, (*sp).c2 );
      _cv_print2( (*sp).c3, (*sp).c4 );

/******************************* direction -2 *********************************/

      sm=pl+(*(pidn++));
      u+=1;

      _print_dir("-2");

      _vector_add(psi,rs.c1,rs.c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c1,chi);
      _vector_add_assign((*sm).c4,chi);

      _vector_sub(psi,rs.c2,rs.c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c2,chi);
      _vector_sub_assign((*sm).c3,chi);

      _cv_print2( (*sm).c1, (*sm).c2 );
      _cv_print2( (*sm).c3, (*sm).c4 );

/******************************* direction +3 *********************************/

      sp=pl+(*(piup));
      u+=1;

      _print_dir("+3");

      _vector_i_sub(psi,rs.c1,rs.c3);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c1,chi);
      _vector_i_add_assign((*sp).c3,chi);

      _vector_i_add(psi,rs.c2,rs.c4);
      _cv_print( psi );
      _su3_inverse_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sp).c2,chi);
      _vector_i_sub_assign((*sp).c4,chi);

      _cv_print2( (*sp).c1, (*sp).c2 );
      _cv_print2( (*sp).c3, (*sp).c4 );

/******************************* direction -3 *********************************/

      sm=pl+(*(pidn));
      u+=1;

      _print_dir("-3");

      _vector_i_add(psi,rs.c1,rs.c3);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c1,chi);
      _vector_i_sub_assign((*sm).c3,chi);

      _vector_i_sub(psi,rs.c2,rs.c4);
      _cv_print( psi );
      _su3_multiply(chi,*u,psi);
      _cv_print( chi );
      _vector_sub_assign((*sm).c2,chi);
      _vector_i_add_assign((*sm).c4,chi);

      _cv_print2( (*sm).c1, (*sm).c2 );
      _cv_print2( (*sm).c3, (*sm).c4 );
}

