
/**********************************************************************************************************************************/
/************************************  Useful routines for a Preconditioned Iterative Solver  *************************************/
/**********************************************************************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include "bem_p_itslv.h"

void dgemv_(char *trans,int *m,int *n,double *alpha,double *a,int *lda,double *x,int *incx,double *beta,double *y,int *incy);


void coo2csr(int n, int nnz, double *ca, int *ia, int *ja)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/************************** In place conversion of a matrix stored in COOrdinate (COO) format into ********************************/
/************************************************* a matrix stored in Compressed Sparse Row (CSR) format **************************/
/**********************************************************************************************************************************/

/* Developer: Sylvain Nintcheu Fata */
/* Version:   V.1.1                 */
/* Released:  Jun 14, 2012          */

 
/* Given a sparse matrix A stored in COO format in ca, ca == Compressed A    */
/* Convert ca from COO to CSR format                                         */
/* Note: The sparse matrix A is assumed to be a usual two-dimensional array  */
/* ca == Compressed A == Sparse matrix containing the non-zero elements of A */
/* n == Length of a row in A                                                 */
/* nnz == Number of non-zero entries in A                                    */
/* Note: ca[nnz],ia[nnz],ja[nnz]                                             */

/* On entry: the matrix ca is stored in COO format                           */
/* ia[k] = Row index in A of ca[k], i.e., ca[k]=A[ia[k]][ja[k]]              */
/* ja[k] = Column index in A of ca[k], i.e., ca[k]=A[ia[k]][ja[k]]           */

/* On return: the matrix ca is stored in CSR format                          */
/* ia[k] = Pointer in ca of the beginning of each row of A                   */
/* ja[k] = Column index in A of ca[k], i.e., ca[k]=A[ia[k]][ja[k]]           */


 int i,j,k,inext,jnext,init,ipos,*ia_tmp;
 double t,tnext;



    if ( (ia_tmp = (int *)calloc(n+1,sizeof(int))) == NULL ) /* If ia_tmp is not successfully allocated */
    {printf("coo2csr: Allocate array \"ia_tmp\" failed\n"); exit(1);}

/* Determine the number of non-zero entries in each row of A */
    for (k=0; k<nnz; k++)
    {
       i = ia[k];
       ia_tmp[i+1]++;
    }

/* Determine the pointer in ca of the beginning of each row of A */
    for (i=1; i<n; i++) ia_tmp[i] += ia_tmp[i-1];

/* Chasing process */
    for (init=0, k=0;;)
    {
       t = ca[init]; i = ia[init]; j = ja[init]; ia[init] = -1;
       while(k<nnz)
       {
          k++;
          ipos = ia_tmp[i]; /* Current row number is i, determine where to go */
          tnext = ca[ipos]; inext = ia[ipos]; jnext = ja[ipos]; /* Save the chased element */
          ca[ipos] = t; ja[ipos] = j; /* Then occupy its location */
          ia_tmp[i] = ipos+1; /* Update pointer information for next element to come in row i */
            if (ia[ipos] < 0) break;
          t = tnext; i = inext; j = jnext; ia[ipos] = -1; /* Determine next element to be chased */
       }

       if (k == nnz) break;
       
       for (;;)
       {
         init++;
	 if ((init >= nnz) || (ia[init] > -1)) break;
       }
       
       if (init >= nnz) break;
    }
    
    for (i=0; i<n; i++) ia[i+1] = ia_tmp[i];
    ia[0]=0; free(ia_tmp);
    
}


void csr_ilu0(int n, double *ca, int *ia, int *ja)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/**************************************************** Zero Fill-in ILU: ILU(0) ****************************************************/
/**** In place Incomplete LU factorization (ILU(0)) for a general sparce matrix ca stored in Compressed Sparse Row format (CSR) ***/
/**********************************************************************************************************************************/

/* Developer: Sylvain Nintcheu Fata */
/* Version:   V.1.1                 */
/* Released:  Jun 14, 2012          */

 
/* Given a sparse matrix A stored in CSR format in ca, ca == Compressed A    */
/* Compute the Zero Fill-in ILU: ILU(0) of A                                 */
/* Note: The sparse matrix A is assumed to be a usual two-dimensional array  */
/* ca == Compressed A == Sparse matrix containing the non-zero elements of A */
/* n == Length of a row in A                                                 */
/* nnz == Number of non-zero entries in A                                    */
/* Note: ca[nnz],ia[n+1],ja[nnz]                                             */

/* On entry: the matrix ca is stored in CSR format                           */
/* ia[k] = Pointer in ca of the beginning of each row of A                   */
/* ja[k] = Column index in A of ca[k], i.e., ca[k]=A[ia[k]][ja[k]]           */

/* On return: the matrix ca, again stored in CSR format,                     */
/*            contains the L and U factors together                          */


 int i,j,jj,k;
 int *iaw, *idiag_a;



   if ( (iaw = (int *)malloc(n*sizeof(int))) == NULL ) /* If iaw is not successfully allocated */
   {printf("csr_ilu0: Allocate array \"iaw\" failed\n"); exit(1);}

   if ( (idiag_a = (int *)malloc(n*sizeof(int))) == NULL ) /* If idiag_a is not successfully allocated */
   {printf("csr_ilu0: Allocate array \"idiag_a\" failed\n"); exit(1);}

   for (k=ia[0]; k<ia[1]; k++)
      if (ja[k] == 0)
      {
	 idiag_a[0] = k; /* Position in ca of A[0][0]  */
	 break;
      }

   for (k=0; k<n; k++) iaw[k] = -1;
   
   for (i=1; i<n; i++) /* Loop over the remaining rows of A */
   {
      for (k=ia[i]; k<ia[i+1]; k++)
      {
	 iaw[ja[k]] = k;
	 if (ja[k] == i) idiag_a[i] = k; /* Position in ca of A[i][i] */
      }

      for (k=0; k<i; k++) /* Loop over previous rows k=0,...,i-1 */
      {
         if (iaw[k] != -1)
	 {
	   ca[iaw[k]] /= ca[idiag_a[k]]; /* A[i][k] = A[i][k]/A[k][k] */
	    for (jj=ia[k]; jj<ia[k+1]; jj++)
	    {
	       j = ja[jj]; /* j == Column index in the k-th row */
		if (j > k)
		  if (iaw[j] != -1) 
		     ca[iaw[j]] -= ca[iaw[k]]*ca[jj]; /* A[i][j] = A[i][j] - A[i][k]*A[k][j] */
	    }
	 }
      }

      for (k=ia[i]; k<ia[i+1]; k++) iaw[ja[k]] = -1;

   }

   free(iaw); free(idiag_a);

}


void csr_ilu0sol(int n, double *ca, int *ia, int *ja, double *b)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/************************************* Solve the linear system A*x=b via an LU decomposition **************************************/
/************************************************************ A = L*U *************************************************************/
/**********************************************************************************************************************************/

/* Developer: Sylvain Nintcheu Fata, Oak Ridge National Laboratory */
/* Version:   V.1.0                                                */
/* Released:  Apr 21, 2011                                         */


/* Given a sparse matrix A stored in Compressed Sparse Row (CSR) format in ca */
/* Solve the system: A*x=b, ca == Compressed A                                */
/* Note: The sparse matrix A is assumed to be a usual two-dimensional array   */
/* ca == Compressed A == Sparse matrix containing the non-zero elements of A  */
/* n == Length of a row in A                                                  */
/* nnz == Number of non-zero entries in A                                     */
/* Note: ca[nnz],ia[n+1],ja[nnz]                                              */

/* On entry: the matrix ca is stored in CSR format                            */
/* ia[k] = Pointer in ca of the beginning of each row of A                    */
/* ja[k] = Column index in A of ca[k], i.e., ca[k]=A[ia[k]][ja[k]]            */
/* b == Right-hand side of the linear system A*x=b                            */

/* On return: b=x == Solution of the linear sytem A*x=b                       */


 int i,k,ii=-1;
 double x;



/* Forward sweep: L*y=b */
   for (i=1; i<n; i++)
   {
      x = 0.0;
      for (k=ia[i]; k<ia[i+1]; k++)
         if (ja[k] < i) x += ca[k]*b[ja[k]]; /* x = x + L[i][k]*b[k] */
      b[i] -= x;
   }


/* Backward sweep: U*x=y */
   for (i=n-1; i>=0; i--)
   {
      x = 0.0;
      for (k=ia[i]; k<ia[i+1]; k++)
      {
         if (ja[k] > i) x += ca[k]*b[ja[k]]; /* x = x + U[i][k]*b[k] */
	 else if (ja[k] == i)  ii = k;
      }
      b[i] = (b[i] - x)/ca[ii];
   }


}


void mat_vec(int m, double *x, double *y)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/******************************************** Compute the matrix-vector product: y=g*x ********************************************/
/**********************************************************************************************************************************/

/* Developer: Sylvain Nintcheu Fata, Oak Ridge National Laboratory */
/* Version:   V.1.0                                                */
/* Released:  Apr 21, 2011                                         */


/* Note: m == Length of vectors x and y, i.e. x[m] and y[m] */
   extern double *g;   /* g == Discretized BIE matrix or Left-hand side of the BEM equation */

   char tr;
   int incx,incy;
   double alp,bet;



     tr = 'n'; alp = 1.0; incx = 1; bet = 0.0; incy = 1;
     dgemv_(&tr,&m,&m,&alp,g,&m,x,&incx,&bet,y,&incy); /* y = matmul(g,x) */

}


void ilu0_l_pcond(int m, double *x)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/****************************************** Compute the matrix-vector product: y=M^{-1}*x *****************************************/
/************************************************** i.e. solve the system: M*y=x **************************************************/
/**********************************************************************************************************************************/

/* Developer: Sylvain Nintcheu Fata, Oak Ridge National Laboratory */
/* Version:   V.1.0                                                */
/* Released:  Apr 21, 2011                                         */


/* Note: m == Length of vectors x, i.e. x[m]      */
/* Note: M is a left preconditioner               */
/* Note: The solution y is written in x on output */
   /* g == Discretized BIE matrix or Left-hand side of the BEM equation */
   extern double *gcsr;      /* gcsr == Sparse approximation of the Discretized BIE matrix g in Compressed Sparse Row (CSR) format */
   extern int *igcsr,*jgcsr; /* igcsr == Pointers in gcsr of the beginning of each row of g */
                             /* jgcsr == Column indices of the entries of gcsr as stored in the Discretized BIE matrix g */

    csr_ilu0sol(m,gcsr,igcsr,jgcsr,x); /* Solve the system: M*y=x, where M=gcsr */

}
