#include <stdio.h>
#include <stdlib.h>
#include "gbem_util.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 mnd_ptl(void); /* Find a boundary node in every class of multiple nodes at which the potential is prescribed */


void gbem_lap_lrhs(void)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/**********************************  GALERKIN BEM for 3D LAPLACE EQUATION: SINGULAR FORMULATION  **********************************/
/************************************  3-NODED TRIANGULAR ELEMENT: SEMI-ANALYTIC INTEGRATION  *************************************/
/************************************************  PIECEWISE LINEAR APPROXIMATION  ************************************************/
/**********************************  Form the left- and right-hand sides of the discretized BIE  **********************************/
/**********************************************************************************************************************************/

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


/* Global variables */
   extern int nbnd;             /* nbnd == Total number of boundary nodes */
   extern int *ndbc;            /* ndbc[i] = {0,1} ==> {Dirichlet,Neunamm} boundary condition is prescribed at the i-th boundary node */
   extern int nmltplnd;         /* nmltplnd == Number of Multiple nodes (or Number of class of Multiple Nodes) on the boundary mesh */
   extern mltndinfo_t *mltplnd; /* mltplnd[k] == Structure containing information about the k-th class of multiple nodes */
   extern double *h, *g;        /* h == Potential influence matrix, g == Flux influence matrix */
   extern double *rhs;          /* rhs == Right-hand side of the Discretized BIE */
   extern double *phi, *flx;    /* phi == Vector containing boundary potentials, flx == Vector containing boundary fluxes */
   extern double *pbv;          /* pbv == Vector containing Prescribed Boundary Values */

/* Local variables */
   char tr;
   int i,j,k,l,n,incx,incy,ni,nl,ii;
   double alp,bet;



/*** Initialization: Prescribed boundary conditions ==> flux and potential vectors */
    if ( (phi = (double *)malloc(nbnd*sizeof(double))) == NULL ) /* If phi is not successfully allocated */
    {printf("gbem_lap_lrhs: Allocate array \"phi\" failed\n"); exit(1);}

    if ( (flx = (double *)malloc(nbnd*sizeof(double))) == NULL ) /* If flx is not successfully allocated */
    {printf("gbem_lap_lrhs: Allocate array \"flx\" failed\n"); exit(1);}

    for (k=0; k< nbnd; k++) /* Loop over all boundary nodes */
    {
       if (ndbc[k] == 0) /* ndbc[k] = 0 ==> Dirichlet data is prescribed at the k-th boundary node */
       {phi[k] = pbv[k]; flx[k] = 0.0;}
       else /* ndbc[k] = 1 ==> Neumann data is prescribed at the k-th boundary node */
       {phi[k] = 0.0; flx[k] = pbv[k];}
    }

    free(pbv);

    mltpl_nd(); /* Find Multiple nodes on the boundary mesh */
    mnd_ptl();  /* Find a boundary node in every class of multiple nodes at which the potential is prescribed */

    if (nmltplnd != 0) /* If there are multiple nodes on the boundary mesh */
    {
       for (k=0; k<nmltplnd; k++) /* Loop over all class of multiple nodes */
       {
          if (mltplnd[k].pnd != -1) /* if there exist in the k-th class a node with Global index mltplnd[k].pnd at */
        			    /* which the potential is prescribed                                           */
             for (j=0; j<mltplnd[k].nn; j++) /* Loop over all multiple nodes in the k-th class */
        	phi[mltplnd[k].id[j]] = phi[mltplnd[k].pnd]; /* Assign potential by continuity */
       }
    }

   if ( (rhs = (double *)malloc(nbnd*sizeof(double))) != NULL ) /* If rhs is successfully allocated */
   {
      /* rhs = matmul(h,phi) - matmul(g,flx) */
      tr = 'n'; alp = 1.0; incx = 1; bet = 0.0; incy = 1;
      dgemv_(&tr,&nbnd,&nbnd,&alp,g,&nbnd,flx,&incx,&bet,rhs,&incy); /* rhs = matmul(g,flx) */

      bet = -1.0;
      dgemv_(&tr,&nbnd,&nbnd,&alp,h,&nbnd,phi,&incx,&bet,rhs,&incy); /* rhs = matmul(h,phi) - rhs */
    }
    else
    {printf("gbem_lap_lrhs: Allocate array \"rhs\" failed\n"); exit(1);}

/*** Rearrange columns: Form the Left-hand side coefficient matrix in g */
    for (k=0; k<nbnd; k++) /* Loop over all boundary nodes */
       if (ndbc[k] == 1) /* if Neumann data is prescribed at the k-th boundary node */
       {
          l = nbnd*k; /* l == Column stride */
	  for (i=0; i<nbnd; i++) /* Loop over all boundary nodes */
	  {
	     j = i+l; /* Column-major order in h[nbnd][nbnd] and g[nbnd][nbnd] matrices */
	     g[j] = -h[j]; /* g[i][k] = -h[i][k] */
	  }
       }

    free(h);

/*** Enforcing continuity of potentials in g */
    if (nmltplnd != 0) /* if the surface mesh has Multiple nodes */
    {
       for (k=0; k<nmltplnd; k++) /* Loop over all class of multiple nodes */
       {
	  if (mltplnd[k].pnd != -1) /* if there exist in the k-th class a node with Global index mltplnd[k].pnd at */
	  {		            /* which the potential is prescribed                                           */
	     for (j=0; j<mltplnd[k].nn; j++) /* Loop over all multiple nodes in the k-th class */
	     {
	        i = mltplnd[k].id[j]; /* i = Global index of the j-th node in the k-th class of multiple nodes */
	        n = nbnd*i; /* n == Column stride */
		if (ndbc[i] == 1) /* if the flux is prescribed at the i-th boundary node */
		{
		   for (l=0; l<nbnd; l++) /* Loop over all boundary nodes */
		   {
		      g[l+n] = 0.0; g[i+nbnd*l] = 0.0; /* g[l][i] = 0.0;  g[i][l] = 0.0 */
		      
		   }
		   g[i+n] = 1.0; rhs[i] = phi[mltplnd[k].pnd]; /* g[i][i] = 1.0; rhs[i] = phi[mltplnd[k].pnd] */
		}
	     }
	  }
	  else /* there is no potential node in the k-th class of multiple nodes ==> ONLY flux nodes in the k-th class */
	  {
	     i = mltplnd[k].id[0]; /* i = Global index of the 1st node in the k-th class of multiple nodes */
	     incx = nbnd*i; /* incx == Column stride */
	     for (j=1; j<mltplnd[k].nn; j++) /* Loop over the remaining nodes in the k-th class of multiple nodes */
	     {
	        l = mltplnd[k].id[j]; /* l = Global index of the j-th node in the k-th class of multiple nodes */
		incy = nbnd*l; /* incy == Column stride */
		  for (n=0; n<nbnd; n++) /* Loop over all boundary nodes */
		  {
		     ni = n+incx; nl = n+incy;
		     g[ni] += g[nl]; /* g[n][i] += g[n][l] <==> add columns */
		     g[nl] = 0.0;    /* g[n][l] = 0.0 */
		  }

		  for (n=0; n<nbnd; n++) /* Loop over all boundary nodes */
		  {
		     ii = nbnd*n;
		     ni = i+ii; nl = l+ii;
		     g[ni] += g[nl]; /* g[i][n] += g[l][n] <==> add rows */
		     g[nl] = 0.0;    /* g[l][n] = 0.0 */
		  }
		  g[l+incy] = 1.0; rhs[i] += rhs[l]; rhs[l] = 0.0; /* g[l][l] = 1.0; rhs[i] += rhs[l]; rhs[l] = 0.0 */
	     }
	  }
       }
    }

}


void mnd_ptl(void)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/*********************************************  GALERKIN BEM for 3D LAPLACE EQUATION  *********************************************/
/******************  Find a boundary node in every class of multiple nodes at which the potential is prescribed  ******************/
/**********************************************************************************************************************************/

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


/* Global variables */
   extern int *ndbc;    /* ndbc[i] = {0,1} ==> {Dirichlet,Neunamm} boundary condition is prescribed at the i-th boundary node */
   extern int nmltplnd; /* nmltplnd == Number of Multiple nodes (or Number of class of Multiple Nodes) on the boundary mesh */
   extern mltndinfo_t *mltplnd; /* mltplnd[k] == Structure containing information about the k-th class of multiple nodes */

/* Local variables */
   int i,j;



    if (nmltplnd != 0) /* if the surface mesh has Multiple nodes */
    {
 	 for (i=nmltplnd-1; i>=0; i--) /* Loop over all multiple nodes */
 	 {
/*** Find a boundary node in the i-th class of multiple nodes at which the potential is prescribed */
	     for (j=0;;)
	     {
	 	if (ndbc[mltplnd[i].id[j]] == 0)
	 	{
	 	  mltplnd[i].pnd = mltplnd[i].id[j]; /* There is in the i-th class a node with global index mltplnd[i].pnd */
	 					     /* at which the potential is prescribed				   */
	 	  break;
	 	}
	 	else if (j == mltplnd[i].nn-1)
	 	{
	 	  mltplnd[i].pnd = -1; /* There is no potential node in the i-th class of multiple nodes */
	 	  break;
	 	}
	 	else  j++;
	
	     }
/*** End Find a boundary node in the i-th class of multiple nodes at which the potential is prescribed */
 	 }
    }

}
