
/*******************************************************************************
*
* File wspace.c
*
* Copyright (C) 2006,2007 Martin Luescher, 2011 Andrea Nobile
*
* This software is distributed under the terms of the GNU General Public
* License (GPL)
*
* Workspace administration
*
* The externally accessible functions are
*
*   spinor **reserve_ws(int n)
*     Reserves a new workspace of n global single-precision spinor fields
*     and returns the array ws[0],..,ws[n-1] of the base addresses of the
*     fields in the workspace. No workspace is reserved and a NULL pointer
*     is returned if n<=0
*
*   int release_ws(void)
*     Releases the workspace of global single-precision spinor fields that
*     was last reserved and returns the number of fields that are released
*
*   int ws_size(void)
*     Returns the number of global single-precision spinor fields that
*     are currently reserved
*
*   spinor_dble **reserve_wsd(int n)
*     Reserves a new workspace of n global double-precision spinor fields
*     and returns the array wsd[0],..,wsd[n-1] of the base addresses of the
*     fields in the workspace. No workspace is reserved and a NULL pointer
*     is returned if n<=0
*
*   int release_wsd(void)
*     Releases the workspace of global double-precision spinor fields that
*     was last reserved and returns the number of fields that are released
*
*   int wsd_size(void)
*     Returns the number of global double-precision spinor fields that
*     are currently reserved
*
*   complex **reserve_wv(int n)
*     Reserves a new workspace of n global single-precision vector fields
*     and returns the array wv[0],..,wv[n-1] of the base addresses of the
*     fields in the workspace. No workspace is reserved and a NULL pointer
*     is returned if n<=0
*
*   int release_wv(void)
*     Releases the workspace of global single-precision vector fields that
*     was last reserved and returns the number of fields that are released
*
*   int wv_size(void)
*     Returns the number of global single-precision vector fields that
*     are currently reserved
*
*   complex_dble **reserve_wvd(int n)
*     Reserves a new workspace of n global double-precision vector fields
*     and returns the array wvd[0],..,wvd[n-1] of the base addresses of the
*     fields in the workspace. No workspace is reserved and a NULL pointer
*     is returned if n<=0
*
*   int release_wvd(void)
*     Releases the workspace of global double-precision vector fields that
*     was last reserved and returns the number of fields that are released
*
*   int wvd_size(void)
*     Returns the number of global double-precision vector fields that
*     are currently reserved
*
* Notes:
*
* By definition a workspace is a set of global single- or double-precision
* fields which is reserved for the current program. This module allows to
* assign and release the required workspaces dynamically in such a way that
* the privacy of the workspaces is guaranteed
*
* The total workspace is the set of all allocated fields of a given type.
* All programs (even the main program) must reserve the required workspaces
* and they must release them before the program returns to the calling program
*
* It is possible to reserve several workspaces of the same type in a given
* program. In this case, a corresponding number of calls to w*_release()
* is required to release all the workspaces that were reserved
*
*******************************************************************************/

#define WSPACE_C

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mpi.h"
#include "su3.h"
#include "start.h"
#include "flags.h"
#include "global.h"

static int nst=0,iws=0,nwst=0,*nws;
static int nsdt=0,iwsd=0,nwsdt=0,*nwsd;

static spinor **ws;
static spinor_dble **wsd;
//static complex **wv;
//static complex_dble **wvd;


static void alloc_nws(void)
{
   int n;

   error_root(nwst!=0,1,"alloc_nws [wspace.c]","Fields are in use");
   
   if (nst>0)
   {
      afree(nws);
      afree(ws);
      nws=NULL;
      ws=NULL;
   }

   nst=no_s;
   iws=0;
   nwst=0;

   if (nst>0)
   {
      nws=amalloc(nst*sizeof(int),3);
      ws=amalloc(nst*sizeof(*ws),3);

      error((nws==NULL)||(ws==NULL),1,"alloc_nws [wspace.c]",
             "Unable to allocated index arrays");

      for (n=0;n<nst;n++)
      {
         nws[n]=0;
         ws[n]=NULL;
      }
   }
}


spinor **reserve_ws(int n)
{
   int iprms[1],i,ia;

   if (NPROC>1)
   {
      iprms[0]=n;

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

      error(iprms[0]!=n,1,"reserve_ws [wspace.c]",
            "Parameter n is not global");
   }

   if (nst!=no_s)
      alloc_nws();

   if (n>0)
   {
      error((nwst+n)>nst,1,"reserve_ws [wspace.c]",
            "Requested too many fields (tot=%d,use=%d,req=%d)",nst,nwst,n);

      ia=nwst;
      nws[iws]=n;
      nwst+=n;
      iws+=1;

      for (i=ia;i<(ia+n);i++)
         ws[i]=ps[i][0];

      return ws+ia;
   }
   else
      return NULL;
}


int release_ws(void)
{
   int n,i;

   if (nwst==0)
      return 0;
   else
   {
      iws-=1;
      n=nws[iws];
      nwst-=n;
      nws[iws]=0;

      for (i=nwst;i<(nwst+n);i++)
         ws[i]=NULL;
      
      return n;
   }
}


int ws_size(void)
{
   return nwst;
}


static void alloc_nwsd(void)
{
   int n;

   error_root(nwsdt!=0,1,"alloc_nwsd [wspace.c]","Fields are in use");   

   if (nsdt>0)
   {
      afree(nwsd);
      afree(wsd);
      nwsd=NULL;
      wsd=NULL;
   }

   nsdt=no_sd;
   iwsd=0;
   nwsdt=0;

   if (nsdt>0)
   {
      nwsd=amalloc(nsdt*sizeof(int),3);
      wsd=amalloc(nsdt*sizeof(*wsd),3);

      error((nwsd==NULL)||(wsd==NULL),1,"alloc_nwsd [wspace.c]",
             "Unable to allocated index arrays");

      for (n=0;n<nsdt;n++)
      {
         nwsd[n]=0;
         wsd[n]=NULL;
      }
   }
}


spinor_dble **reserve_wsd(int n)
{
   int iprms[1],i,ia;

   if (NPROC>1)
   {
      iprms[0]=n;

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

      error(iprms[0]!=n,1,"reserve_wsd [wspace.c]",
            "Parameter n is not global");
   }

   if (nsdt!=no_sd)
      alloc_nwsd();

   if (n>0)
   {
      error((nwsdt+n)>nsdt,1,"reserve_wsd [wspace.c]",
            "Requested too many fields (tot=%d,use=%d,req=%d)",nsdt,nwsdt,n);

      ia=nwsdt;
      nwsd[iwsd]=n;
      nwsdt+=n;
      iwsd+=1;

      for (i=ia;i<(ia+n);i++)
         wsd[i]=psd[i][0];
      
      return wsd+ia;
   }
   else
      return NULL;
}


int release_wsd(void)
{
   int n,i;

   if (nwsdt==0)
      return 0;
   else
   {
      iwsd-=1;
      n=nwsd[iwsd];
      nwsdt-=n;
      nwsd[iwsd]=0;

      for (i=nwsdt;i<(nwsdt+n);i++)
         wsd[i]=NULL;
      
      return n;
   }
}


int wsd_size(void)
{
   return nwsdt;
}
/*

static void alloc_nwv(int no_v)
{
   int n;

   error_root(nwvt!=0,1,"alloc_nwv [wspace.c]","Fields are in use");
   
   if (nvt>0)
   {
      afree(nwv);
      afree(wv);
      nwv=NULL;
      wv=NULL;
   }

   nvt=no_v;
   iwv=0;
   nwvt=0;

   if (nvt>0)
   {
      nwv=amalloc(nvt*sizeof(int),3);
      wv=amalloc(nvt*sizeof(*wv),3);

      error((nwv==NULL)||(wv==NULL),1,"alloc_nwv [wspace.c]",
             "Unable to allocated index arrays");

      for (n=0;n<nvt;n++)
      {
         nwv[n]=0;
         wv[n]=NULL;
      }
   }
}


complex **reserve_wv(int n)
{
   int iprms[1],i,ia;
   int no_v,nv,nvec;
   complex *v;

   if (NPROC>1)
   {
      iprms[0]=n;

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

      error(iprms[0]!=n,1,"reserve_wv [wspace.c]",
            "Parameter n is not global");
   }

   v=vflds_base(&no_v,&nv,&nvec);
   
   if (nvt!=no_v)
      alloc_nwv(no_v);

   if (n>0)
   {
      error((nwvt+n)>nvt,1,"reserve_wv [wspace.c]",
            "Requested too many fields (tot=%d,use=%d,req=%d)",nvt,nwvt,n);

      ia=nwvt;
      nwv[iwv]=n;
      nwvt+=n;
      iwv+=1;
      v+=ia*nvec;

      for (i=ia;i<(ia+n);i++)
      {
         wv[i]=v;
         v+=nvec;
      }

      return wv+ia;
   }
   else
      return NULL;
}


int release_wv(void)
{
   int n,i;

   if (nwvt==0)
      return 0;
   else
   {
      iwv-=1;
      n=nwv[iwv];
      nwvt-=n;
      nwv[iwv]=0;

      for (i=nwvt;i<(nwvt+n);i++)
         wv[i]=NULL;
      
      return n;
   }
}


int wv_size(void)
{
   return nwvt;
}


static void alloc_nwvd(int no_vd)
{
   int n;

   error_root(nwvdt!=0,1,"alloc_nwvd [wspace.c]","Fields are in use");
   
   if (nvdt>0)
   {
      afree(nwvd);
      afree(wvd);
      nwvd=NULL;
      wvd=NULL;
   }

   nvdt=no_vd;
   iwvd=0;
   nwvdt=0;

   if (nvdt>0)
   {
      nwvd=amalloc(nvdt*sizeof(int),3);
      wvd=amalloc(nvdt*sizeof(*wvd),3);

      error((nwvd==NULL)||(wvd==NULL),1,"alloc_nwvd [wspace.c]",
             "Unable to allocated index arrays");

      for (n=0;n<nvdt;n++)
      {
         nwvd[n]=0;
         wvd[n]=NULL;
      }
   }
}


complex_dble **reserve_wvd(int n)
{
   int iprms[1],i,ia;
   int no_vd,nv,nvec;
   complex_dble *vd;

   if (NPROC>1)
   {
      iprms[0]=n;

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

      error(iprms[0]!=n,1,"reserve_wvd [wspace.c]",
            "Parameter n is not global");
   }

   vd=vdflds_base(&no_vd,&nv,&nvec);
   
   if (nvdt!=no_vd)
      alloc_nwvd(no_vd);

   if (n>0)
   {
      error((nwvdt+n)>nvdt,1,"reserve_wvd [wspace.c]",
            "Requested too many fields (tot=%d,use=%d,req=%d)",nvdt,nwvdt,n);

      ia=nwvdt;
      nwvd[iwvd]=n;
      nwvdt+=n;
      iwvd+=1;
      vd+=ia*nvec;

      for (i=ia;i<(ia+n);i++)
      {
         wvd[i]=vd;
         vd+=nvec;
      }

      return wvd+ia;
   }
   else
      return NULL;
}


int release_wvd(void)
{
   int n,i;

   if (nwvdt==0)
      return 0;
   else
   {
      iwvd-=1;
      n=nwvd[iwvd];
      nwvdt-=n;
      nwvd[iwvd]=0;

      for (i=nwvdt;i<(nwvdt+n);i++)
         wvd[i]=NULL;
      
      return n;
   }
}


int wvd_size(void)
{
   return nwvdt;
}

*/
