
/*******************************************************************************
*
* File Qbnd.c
*
* Copyright (C) 2005 Martin Luescher
*
* This software is distributed under the terms of the GNU General Public
* License (GPL)
*
* Application of the boundary terms Q_dLambda and Q_dLambda* of the hermitian
* Wilson-Dirac operator
*
* The externally accessible functions are
*
*   void Qbnd(block_t *b,int k,int l)
*     Applies the boundary term Q_dLambda to the Weyl field number k on
*     the boundary of the block b and *subtracts* the result from the
*     Dirac field number l on b
*
*   void Qbnds(block_t *b,int k,int l)
*     Applies the boundary term Q_dLambda* to the Dirac field number k on
*     the block b and *assigns* the result to the Weyl field number l on
*     the boundary of b
*
*   void assign_s2sbb(block_t *b,int k,int l)
*     Applies the projector theta_dLambda to the global field number k
*     and assigns the result to the Weyl field number l on the boundary
*     of the block b
*
*   void sub_assign_sbb2s(block_t *b,int k,int l)
*     Expands the Weyl field number k on the boundary of the block b to
*     a Dirac field psi satisfying theta_dLambda*psi=psi and subtracts
*     psi from the global field number l
*
*   void mulg5_sub_assign_sbb2s(block_t *b,int k,int l)
*     Expands the Weyl field number k on the boundary of the block b to
*     a Dirac field psi satisfying theta_dLambda*psi=psi and subtracts
*     dirac5*psi from the global field number l
*
* Notes:
*
* In all cases the Weyl fields at the boundary are the upper two components
* of a Dirac field psi that satisfies theta*psi=psi (see Pbnd.c)
*
* The boundary operators are local to the block and can therefore be called
* locally. A communication may, however, be required in the case the other
* programs. They act globally and require the block b to have exactly the
* same size and local position on all processes
*
*******************************************************************************/

#define QBND_C

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


#if (defined SSE)
#include "sse.h"

static sse_float moh={-0.5f,-0.5f,-0.5f,-0.5f};

static void mul_umat(su3 *u)
{
   _sse_su3_multiply(*u);
}


static void mul_uinv(su3 *u)
{
   _sse_su3_inverse_multiply(*u);
}


void Qbnd(block_t *b,int k,int l)
{
   int *ipp;
   su3 *u,*um;
   weyl *rsk;
   spinor *psl,*rsl,*rsn;
   bndry_t *bb;

   if (error_loc((k<0)||(k>=(*(*b).bb).ns)||(l<0)||(l>=(*b).ns),1,
                 "Qbnd [Qbnd.c]",
                 "Attempt to access unallocated memory space")!=0)
      return;

/********************************** face -0 ***********************************/

   bb=(*b).bb;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   psl=(*b).s[l];
   rsn=psl+(*ipp++);

   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_uinv(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c3,(*rsl).c4);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c3,(*rsl).c4);
   }

/********************************** face +0 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_umat(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c3,(*rsl).c4);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_sub();
      _sse_pair_store((*rsl).c3,(*rsl).c4);
   }

/********************************** face -1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_uinv(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c4,(*rsl).c3);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_i_sub();
      _sse_pair_store((*rsl).c4,(*rsl).c3);
   }

/********************************** face +1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_umat(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c4,(*rsl).c3);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_i_add();
      _sse_pair_store((*rsl).c4,(*rsl).c3);
   }

/********************************** face -2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_uinv(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c4,(*rsl).c3);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_addsub();
      _sse_pair_store((*rsl).c4,(*rsl).c3);
   }

/********************************** face +2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_umat(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c4,(*rsl).c3);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_subadd();
      _sse_pair_store((*rsl).c4,(*rsl).c3);
   }


/********************************** face -3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_uinv(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c3,(*rsl).c4);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_i_subadd();
      _sse_pair_store((*rsl).c3,(*rsl).c4);
   }

/********************************** face +3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   rsn=psl+(*ipp++);
   
   for (;u<um;)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);

      rsl=rsn;
      rsn=psl+(*ipp++);
      _prefetch_spinor(rsn);

      mul_umat(u);

      _sse_pair_load((*rsl).c1,(*rsl).c2);

      rsk+=3;
      _prefetch_weyl(rsk);
      rsk-=2;

      _sse_vector_add();
      _sse_pair_store((*rsl).c1,(*rsl).c2);
      _sse_pair_load((*rsl).c3,(*rsl).c4);

      u+=3;
      _prefetch_su3(u);
      u-=2;

      _sse_vector_i_addsub();
      _sse_pair_store((*rsl).c3,(*rsl).c4);
   }
}


void Qbnds(block_t *b,int k,int l)
{
   int *ipp;
   su3 *u,*um;
   weyl *rsl;
   spinor *psk,*rsk;
   bndry_t *bb;

   if (error_loc((k<0)||(k>=(*b).ns)||(l<0)||(l>=(*(*b).bb).ns),1,
                 "Qbnds [Qbnd.c]",
                 "Attempt to access unallocated memory space")!=0)
      return;

/********************************** face -0 ***********************************/

   bb=(*b).bb;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   psk=(*b).s[k];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c3,(*rsk).c4);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_add();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;
      
      mul_umat(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face +0 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c3,(*rsk).c4);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_sub();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_uinv(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face -1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c4,(*rsk).c3);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_i_add();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_umat(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face +1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c4,(*rsk).c3);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_i_sub();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_uinv(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face -2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c4,(*rsk).c3);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_addsub();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_umat(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face +2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c4,(*rsk).c3);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_subadd();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_uinv(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face -3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c3,(*rsk).c4);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_i_addsub();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_umat(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }

/********************************** face +3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   rsk=psk+(*ipp++);

   for (;u<um;u++)
   {
      _sse_pair_load((*rsk).c1,(*rsk).c2);
      _sse_pair_load_up((*rsk).c3,(*rsk).c4);

      rsk=psk+(*ipp++);
      _prefetch_spinor(rsk);

      _sse_vector_i_subadd();
      _sse_vector_mul(moh);

      u+=3;
      _prefetch_su3(u);
      u-=3;

      mul_uinv(u);

      _sse_pair_store_up((*rsl).c1,(*rsl).c2);
      rsl+=1;
   }
}

#else

static weyl chi;

static void mul_umat(weyl *s,su3 *u,weyl *r)
{
   _su3_multiply((*r).c1,*u,(*s).c1);
   _su3_multiply((*r).c2,*u,(*s).c2);
}

static void mul_uinv(weyl *s,su3 *u,weyl *r)
{
   _su3_inverse_multiply((*r).c1,*u,(*s).c1);
   _su3_inverse_multiply((*r).c2,*u,(*s).c2);
}


void Qbnd(block_t *b,int k,int l)
{
   int *ipp;
   su3 *u,*um;
   weyl *rsk;
   spinor *psl,*rsl;
   bndry_t *bb;

   if (error_loc((k<0)||(k>=(*(*b).bb).ns)||(l<0)||(l>=(*b).ns),1,
                 "Qbnd [Qbnd.c]",
                 "Attempt to access unallocated memory space")!=0)
      return;

/********************************** face -0 ***********************************/

   bb=(*b).bb;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];
   psl=(*b).s[l];

   for (;u<um;u++)
   {
      mul_uinv(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_add_assign((*rsl).c3,chi.c1);
      _vector_add_assign((*rsl).c4,chi.c2);
   }

/********************************** face +0 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_umat(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_sub_assign((*rsl).c3,chi.c1);
      _vector_sub_assign((*rsl).c4,chi.c2);
   }

/********************************** face -1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_uinv(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_i_sub_assign((*rsl).c3,chi.c2);
      _vector_i_sub_assign((*rsl).c4,chi.c1);
   }

/********************************** face +1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_umat(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_i_add_assign((*rsl).c3,chi.c2);
      _vector_i_add_assign((*rsl).c4,chi.c1);
   }

/********************************** face -2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_uinv(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_sub_assign((*rsl).c3,chi.c2);
      _vector_add_assign((*rsl).c4,chi.c1);
   }

/********************************** face +2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_umat(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_add_assign((*rsl).c3,chi.c2);
      _vector_sub_assign((*rsl).c4,chi.c1);
   }


/********************************** face -3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_uinv(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_i_sub_assign((*rsl).c3,chi.c1);
      _vector_i_add_assign((*rsl).c4,chi.c2);
   }

/********************************** face +3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsk=(*bb).s[k];

   for (;u<um;u++)
   {
      mul_umat(rsk,u,&chi);
      rsk+=1;
      rsl=psl+(*ipp);
      ipp+=1;
      _vector_add_assign((*rsl).c1,chi.c1);
      _vector_add_assign((*rsl).c2,chi.c2);
      _vector_i_add_assign((*rsl).c3,chi.c1);
      _vector_i_sub_assign((*rsl).c4,chi.c2);
   }
}


void Qbnds(block_t *b,int k,int l)
{
   int *ipp;
   float r1;
   su3 *u,*um;
   weyl *rsl;
   spinor *psk,*rsk;
   bndry_t *bb;

   if (error_loc((k<0)||(k>=(*b).ns)||(l<0)||(l>=(*(*b).bb).ns),1,
                 "Qbnds [Qbnd.c]",
                 "Attempt to access unallocated memory space")!=0)
      return;

   r1=-0.5f;

/********************************** face -0 ***********************************/

   bb=(*b).bb;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];
   psk=(*b).s[k];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_add(chi.c1,(*rsk).c1,(*rsk).c3);
      _vector_add(chi.c2,(*rsk).c2,(*rsk).c4);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_umat(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face +0 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_sub(chi.c1,(*rsk).c1,(*rsk).c3);
      _vector_sub(chi.c2,(*rsk).c2,(*rsk).c4);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_uinv(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face -1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_i_add(chi.c1,(*rsk).c1,(*rsk).c4);
      _vector_i_add(chi.c2,(*rsk).c2,(*rsk).c3);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_umat(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face +1 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_i_sub(chi.c1,(*rsk).c1,(*rsk).c4);
      _vector_i_sub(chi.c2,(*rsk).c2,(*rsk).c3);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_uinv(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face -2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_add(chi.c1,(*rsk).c1,(*rsk).c4);
      _vector_sub(chi.c2,(*rsk).c2,(*rsk).c3);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_umat(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face +2 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_sub(chi.c1,(*rsk).c1,(*rsk).c4);
      _vector_add(chi.c2,(*rsk).c2,(*rsk).c3);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_uinv(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face -3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_i_add(chi.c1,(*rsk).c1,(*rsk).c3);
      _vector_i_sub(chi.c2,(*rsk).c2,(*rsk).c4);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_umat(&chi,u,rsl);
      rsl+=1;
   }

/********************************** face +3 ***********************************/

   bb+=1;
   ipp=(*bb).ipp;
   u=(*bb).u;
   um=u+(*bb).vol;
   rsl=(*bb).s[l];

   for (;u<um;u++)
   {
      rsk=psk+(*ipp);
      ipp+=1;
      _vector_i_sub(chi.c1,(*rsk).c1,(*rsk).c3);
      _vector_i_add(chi.c2,(*rsk).c2,(*rsk).c4);
      _vector_mul(chi.c1,r1,chi.c1);
      _vector_mul(chi.c2,r1,chi.c2);
      mul_uinv(&chi,u,rsl);
      rsl+=1;
   }
}

#endif

static void cp_w2w(int ifc,int vol,weyl *pk,weyl *pl)
{
   int np,nbf,saddr,raddr,tag;
   float *sbuf,*rbuf;
   MPI_Status stat;

   np=(cpr[0]+cpr[1]+cpr[2]+cpr[3]+ifc)&0x1;
   saddr=npr[ifc^0x1];
   raddr=npr[ifc];

   sbuf=(float*)(pk);
   rbuf=(float*)(pl);
   nbf=12*vol;
   tag=mpi_tag();

   if (np==0)
   {
      MPI_Send(sbuf,nbf,MPI_FLOAT,saddr,tag,MPI_COMM_WORLD);
      MPI_Recv(rbuf,nbf,MPI_FLOAT,raddr,tag,MPI_COMM_WORLD,&stat);
   }
   else
   {
      MPI_Recv(rbuf,nbf,MPI_FLOAT,raddr,tag,MPI_COMM_WORLD,&stat);
      MPI_Send(sbuf,nbf,MPI_FLOAT,saddr,tag,MPI_COMM_WORLD);
   }
}


void assign_s2sbb(block_t *b,int k,int l)
{
   int ifc,mu,iprms[10];
   weyl *pl,*pw;
   spinor *pk;
   bndry_t *bb;

   if (NPROC>1)
   {
      for (mu=0;mu<4;mu++)
      {
         iprms[mu]=(*b).bo[mu];
         iprms[mu+4]=(*b).bs[mu];
      }

      iprms[8]=k;
      iprms[9]=l;

      MPI_Bcast(iprms,10,MPI_INT,0,MPI_COMM_WORLD);

      for (mu=0;mu<4;mu++)
         if ((iprms[mu]!=(*b).bo[mu])||(iprms[mu+4]!=(*b).bs[mu]))
            break;

      error((mu!=4)||(iprms[8]!=k)||(iprms[9]!=l),1,"assign_s2sbb [Qbnd.c]",
             "Block positions and sizes, or other parameters are not global");

      if (error_loc((k<0)||(k>=no_s)||(l<0)||(l>=(*(*b).bb).ns),1,
          "assign_s2sbb [Qbnd.c]",
          "Attempt to access unallocated memory space")!=0)
         return;
   }

   pk=ps[k][0];
   bb=(*b).bb;

   for (ifc=0;ifc<8;ifc++)
   {
      pl=(*bb).s[l];

      if ((*bb).ibn==0)
         assign_s2w[ifc]((*bb).imb,(*bb).vol,pk,pl);
      else
      {
         pw=(weyl*)(pk+VOLUME);
         assign_s2w[ifc]((*bb).imb,(*bb).vol,pk,pw);
         cp_w2w(ifc,(*bb).vol,pw,pl);
      }

      bb+=1;
   }
}


void sub_assign_sbb2s(block_t *b,int k,int l)
{
   int ifc,mu,iprms[10];
   weyl *pk,*pw;
   spinor *pl;
   bndry_t *bb;

   if (NPROC>1)
   {
      for (mu=0;mu<4;mu++)
      {
         iprms[mu]=(*b).bo[mu];
         iprms[mu+4]=(*b).bs[mu];
      }

      iprms[8]=k;
      iprms[9]=l;

      MPI_Bcast(iprms,10,MPI_INT,0,MPI_COMM_WORLD);

      for (mu=0;mu<4;mu++)
         if ((iprms[mu]!=(*b).bo[mu])||(iprms[mu+4]!=(*b).bs[mu]))
            break;

      error((mu!=4)||(iprms[8]!=k)||(iprms[9]!=l),1,
             "sub_assign_sbb2s [Qbnd.c]",
             "Block positions and sizes, or other parameters are not global");

      if (error_loc((k<0)||(k>=(*(*b).bb).ns)||(l<0)||(l>=no_s),1,
          "sub_assign_sbb2s [Qbnd.c]",
          "Attempt to access unallocated memory space")!=0)
         return;
   }

   pl=ps[l][0];
   bb=(*b).bb;

   for (ifc=0;ifc<8;ifc++)
   {
      pk=(*bb).s[k];

      if ((*bb).ibn==0)
         sub_assign_w2s[ifc]((*bb).imb,(*bb).vol,pk,pl);
      else
      {
         pw=(weyl*)(pl+VOLUME);
         cp_w2w(ifc^0x1,(*bb).vol,pk,pw);
         sub_assign_w2s[ifc]((*bb).imb,(*bb).vol,pw,pl);
      }

      bb+=1;
   }
}


void mulg5_sub_assign_sbb2s(block_t *b,int k,int l)
{
   int ifc,mu,iprms[10];
   weyl *pk,*pw;
   spinor *pl;
   bndry_t *bb;

   if (NPROC>1)
   {
      for (mu=0;mu<4;mu++)
      {
         iprms[mu]=(*b).bo[mu];
         iprms[mu+4]=(*b).bs[mu];
      }

      iprms[8]=k;
      iprms[9]=l;

      MPI_Bcast(iprms,10,MPI_INT,0,MPI_COMM_WORLD);

      for (mu=0;mu<4;mu++)
         if ((iprms[mu]!=(*b).bo[mu])||(iprms[mu+4]!=(*b).bs[mu]))
            break;

      error((mu!=4)||(iprms[8]!=k)||(iprms[9]!=l),1,
             "mulg5_sub_assign_sbb2s [Qbnd.c]",
             "Block positions and sizes, or other parameters are not global");

      if (error_loc((k<0)||(k>=(*(*b).bb).ns)||(l<0)||(l>=no_s),1,
          "mulg5_sub_assign_sbb2s [Qbnd.c]",
          "Attempt to access unallocated memory space")!=0)
         return;
   }

   pl=ps[l][0];
   bb=(*b).bb;

   for (ifc=0;ifc<8;ifc++)
   {
      pk=(*bb).s[k];

      if ((*bb).ibn==0)
         mulg5_sub_assign_w2s[ifc]((*bb).imb,(*bb).vol,pk,pl);
      else
      {
         pw=(weyl*)(pl+VOLUME);
         cp_w2w(ifc^0x1,(*bb).vol,pk,pw);
         mulg5_sub_assign_w2s[ifc]((*bb).imb,(*bb).vol,pw,pl);
      }

      bb+=1;
   }
}

