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

void gbem_lap_iex_int_c(int elQ);          /* Coincident integration for element P=Q                  */
void gbem_lap_iex_int_e(int elP, int elQ); /* Edge-adjacent integration for element P and element Q   */
void gbem_lap_iex_int_v(int elP, int elQ); /* Vertex-adjacent integration for element P and element Q */
void gbem_lap_iex_int(int elP, int elQ);   /* Non-Singular integration for element P and element Q    */


void gbem_lap_assem(void)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/**********************************  GALERKIN BEM for 3D LAPLACE EQUATION: SINGULAR FORMULATION  **********************************/
/************************************  3-NODED TRIANGULAR ELEMENT: SEMI-ANALYTIC INTEGRATION  *************************************/
/************************************************  PIECEWISE LINEAR APPROXIMATION  ************************************************/
/*********************************************  Assemble h and g influence matrices  **********************************************/
/**********************************************************************************************************************************/

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

 
/* Global variables */
   extern const int mx_nd_elt; /* mx_nd_elt == Maximum number of nodes per element */
   extern int nbnd,nbelt;    /* nbnd == Total number of boundary nodes */
                             /* nbelt == Total number of boundary elements */
   extern double *h, *g;     /* h == Potential influence matrix <==> Coefficient matrix acting on the vector of boundary potentials */
                             /* g == Flux influence matrix <==> Coefficient matrix acting on the vector of boundary fluxes */
   extern double *EltDiam;   /* EltDiam[k] == Diameter of the k-th boundary element */
   extern double *EltAreax2; /* EltAreax2[k] = 2*Area of the k-th boundary element */
   extern double ***shfe1;   /* shfe1[i][k][l] == l-th shape function evaluated at Gauss point (k,i) for edge-adjacent integration: E' */
   extern double ***shfe2;   /* shfe2[i][k][l] == l-th shape function evaluated at Gauss point (k,i) for edge-adjacent integration: E" */
   extern double ***shfv;    /* shfv[i][k][l] == l-th shape function evaluated at Gauss point (k,i) for vertex-adjacent integration    */
   extern int ng1,ng2,ng3;       /* ng1 == Number of Gauss-Legendre points over a segment [0,1] for Singular integrations */
			         /* ng2 == Number of Gauss-Legendre points over a segment [0,1] for Quasi-singular integration */
			         /* ng3 == Number of Gauss-Legendre points over a segment [0,1] for Non-singular integration */
   extern double *xi1,*xi2,*xi3; /* xi1 == Gauss-Legendre points over a segment [0,1] for Singular integrations */
			         /* xi2 == Gauss-Legendre points over a segment [0,1] for Quasi-singular integration */
			         /* xi3 == Gauss-Legendre points over a segment [0,1] for Non-singular integration */
   extern double **wwg1; /* wwg1[i][k] = wg1[i]*wg1[k], where wg1[k] is the k-th Gauss-Legendre weight factor corresponding to xi1[k] */
   extern double **wwg2; /* wwg2[i][k] = wg2[i]*wg2[k], where wg2[k] is the k-th Gauss-Legendre weight factor corresponding to xi2[k] */
   extern double **wwg3; /* wwg3[i][k] = wg3[i]*wg3[k], where wg3[k] is the k-th Gauss-Legendre weight factor corresponding to xi3[k] */
   extern double **dwrk; /* Temporary working array dwrk[mx_nd_elt][mx_nd_elt] used in function "int_type" (see gbem_util.c) */

/* Local variables */
   char flag='U'; /* flag='U' <==> Integration type is Undefined */
   int i,k,elP,elQ,snbnd;



   snbnd = nbnd*nbnd;
   if ( (h = (double *)calloc(snbnd,sizeof(double))) == NULL ) /* If h is not successfully allocated */
   {printf("gbem_lap_assem: Allocate array \"h\" failed\n"); exit(1);} /* h[nbnd][nbnd] */
    
   if ( (g = (double *)calloc(snbnd,sizeof(double))) == NULL ) /* If g is not successfully allocated */
   {printf("gbem_lap_assem: Allocate array \"g\" failed\n"); exit(1);} /* g[nbnd][nbnd] */
   
/*** Assemble h and g influence matrices **********************************************************/
 	  for (elP=0; elP<nbelt; elP++) /* Loop over all boundary elements */
	  {
 	     gbem_lap_iex_int_c(elP); /* Element P and element Q coincide ==> Coincident integration */

 	     for (elQ=elP+1; elQ<nbelt; elQ++) /* Loop over the remaining boundary elements */
	     {
 	  	if (EltAreax2[elQ] >= EltAreax2[elP]) /* EltAreax2[elQ] = 2*area(elQ) */
		{

 	  	   int_type(elP,elQ,&flag); /* Determine integration type ==> get flag */

 	  	    if ( flag == 'E' ) 	             /* If element P and element Q share a common edge */
 	  		gbem_lap_iex_int_e(elP,elQ); /* Edge-adjacent integration                      */

 	  	    else if( flag == 'V' )           /* If element P and element Q share a common vertex */
			gbem_lap_iex_int_v(elP,elQ); /* Vertex-adjacent integration                      */
 
 	  	    else			     /* Element P and element Q are not adjoining */
 	  		gbem_lap_iex_int(elP,elQ);   /* Non-Singular integration                  */
 	  	}
		else /* EltAreax2[elQ] < EltAreax2[elP] */
		{

 	  	   int_type(elQ,elP,&flag); /* Determine integration type ==> get flag */

 	  	    if ( flag == 'E' ) 	             /* If element Q and element P share a common edge */
 	  		gbem_lap_iex_int_e(elQ,elP); /* Edge-adjacent integration                      */
 
 	  	    else if( flag == 'V' )           /* If element Q and element P share a common vertex */
 	  		gbem_lap_iex_int_v(elQ,elP); /* Vertex-adjacent integration                      */
 
 	  	    else			     /* Element Q and element P are not adjoining */
 	  		gbem_lap_iex_int(elQ,elP);   /* Non-Singular integration                  */
 	  	}
 	     } /* Loop over the remaining boundary elements */
 	  } /* Loop over all boundary elements */
/*** End Assemble h and g influence matrices ******************************************************/

   free(xi1); free(xi2); free(xi3);
   free(EltAreax2); free(EltDiam);
   
   for (i=0; i<ng1; i++) /* Loop over all Gauss points */
   {   
      for (k=0; k<ng1; k++) /* Loop over all Gauss points */
      {
         free(shfv[i][k]); free(shfe1[i][k]); free(shfe2[i][k]);
      }
      free(shfv[i]); free(shfe1[i]); free(shfe2[i]); free(wwg1[i]);
   }
   free(shfv); free(shfe1); free(shfe2); free(wwg1);
   
   for (i=0; i<ng2; i++) free(wwg2[i]);
   free(wwg2);
   
   for (i=0; i<ng3; i++) free(wwg3[i]);
   free(wwg3);

   for (i=0; i<mx_nd_elt; i++) free(dwrk[i]);
   free(dwrk);

}
