#include <math.h>


void gbem_lap_iex_int_c(int elQ)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/**********************************  GALERKIN BEM for 3D LAPLACE EQUATION: SINGULAR FORMULATION  **********************************/
/***************************************  3-NODED TRIANGULAR ELEMENT: ANALYTIC INTEGRATION  ***************************************/
/************************************************  PIECEWISE LINEAR APPROXIMATION  ************************************************/
/*******************************  EXact Inner integral with linear distribution on a flat triangle  *******************************/
/****************************************************  Coincident integration  ****************************************************/
/**********************************************************************************************************************************/

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

 
/* Note: elQ == Global index of the boundary element Q */
   extern const int mx_nd_elt;   /* mx_nd_elt == Maximum number of nodes per element */
   extern int smx_nd_elt;        /* smx_nd_elt == mx_nd_elt*mx_nd_elt */
   extern int nbnd;              /* nbnd == Total number of boundary nodes */
   extern int **belt;            /* belt[i][0:2] == Global indices of boundary nodes on the i-th element */
   extern int *pp, *qq;          /* pp[k] == Global index of the k-th node of the boundary element P=Q */
                                 /* qq[k] == Global index of the k-th node of the boundary element Q=P */
   extern double pi;             /* pi = 3.1415926535897932 */
   extern double **xvElt,*zvElt; /* xvElt[k][0] == Base of the k-th boundary element */
				 /* xvElt[k][1] == Geometric parameter associated with the k-th boundary element */
				 /* zvElt[k] == Height of the k-th boundary element */
   extern double **thetaElt;     /* thetaElt[k][i] == Angle at the i-th vertex of the k-th boundary element */
   extern double *EltAreax2;     /* EltAreax2[k] = 2*Area of the k-th boundary element */
   extern double *int_p, *int_f; /* int_p == Local contribution for potential influence matrix */
				 /* int_f == Local contribution for flux influence matrix */
   extern double *h, *g;         /* h == Potential influence matrix, g == Flux influence matrix */

   int k,j,row,col,cl_strd,cl_strd_loc;
   int qqLoc[mx_nd_elt];
   double qr2,alpha2,alpha3;
   double xv[3],zv[3],pr[2],theta[3];
   double rhoSD[3]; /* rhoSD[k] == length of the k-th side of element Q */
   double a,b,c; /* Geometric parameters of the boundary element Q=P */
   double calpk,salpk,lf2,lf3,dlt,dltp2,cf,aab,aab_12,aab_60,k2,k3,c_b;
   double rh2,rh3,ln1,ln2,ln3,bc,bmc,bbmc,bbmc_rh2,bc_rh3,ln2_rh2p3,ln3_rh3p3,rh2p2,rh2p3,rh2p4,rh3p2,rh3p3,rh3p4;
   double ap2,bp2,dltp2_rh2p2,dltp2_rh3p2,ccf2_15,ccf3_15,ccf2_75,ccf3_75,rh3_rh2p2,rh2_rh3p2;
   double intK1,intK2,intK3,intK12,intK13,intK23,Irhoz,Irhoxz,Irhozz,Ichizz,Ichixzz,Ichizzz;
   double intK[smx_nd_elt],intN[smx_nd_elt]; /* Column-major order in intK[mx_nd_elt][mx_nd_elt],intN[mx_nd_elt][mx_nd_elt] */


   
    for (col=0; col<mx_nd_elt; col++) /* Loop over the nodes of element Q */
    {
       qq[col] = belt[elQ][col]; /* qq[col] == Global index of the col-th node of the boundary element Q */
       pp[col] = qq[col]; /* Element P is equal to element Q */
       cl_strd_loc = mx_nd_elt*col; /* cl_strd_loc == Local Column stride */
       for (row=0; row<mx_nd_elt; row++) /* Loop over the nodes of element P */
	  int_f[row + cl_strd_loc] = 0.0;
    }

    for (k=0; k<3; k++) /* Loop over all vertices of element Q */
       theta[k] = thetaElt[elQ][k];

    xv[0] = xvElt[elQ][0]; xv[2] = xvElt[elQ][1];
    zv[0] = 0.0;
    zv[1] = zvElt[elQ];
    zv[2] = zv[1];

    cf = zv[1]*zv[1]; xv[1] = xv[2]-xv[0];
    rhoSD[0] = xv[0]; rhoSD[1] = sqrt(xv[1]*xv[1] + cf); rhoSD[2] = sqrt(xv[2]*xv[2] + cf);
	 
    alpha2 = pi-theta[1]; alpha3 = pi+theta[0]; /* alpha1 = 0.0 */
	
    dlt = EltAreax2[elQ]; /* dlt = xv[0]*zv[1] */
    lf2 = pi*dlt/6.0;
    lf3 = lf2/2.0;

	int_p[0] = lf2; int_p[1] = lf3; int_p[2] = lf3; /* int_p(1,1) = lf2; int_p(2,1) = lf3; int_p(3,1) = lf3 */
	int_p[3] = lf3; int_p[4] = lf2; int_p[5] = lf3; /* int_p(1,2) = lf3; int_p(2,2) = lf2; int_p(3,2) = lf3 */
	int_p[6] = lf3; int_p[7] = lf3; int_p[8] = lf2; /* int_p(1,3) = lf3; int_p(2,3) = lf3; int_p(3,3) = lf2 */

	    for (col=0; col<mx_nd_elt; col++) /* Loop over the nodes of element Q */
	    {
	       cl_strd_loc = mx_nd_elt*col; /* cl_strd_loc == Local Column stride */
	       cl_strd = nbnd*qq[col]; /* cl_strd == Column stride */
	       for (row=0; row<mx_nd_elt; row++) /* Loop over the nodes of element P */
	       {
	          k=pp[row] + cl_strd; /* Column-major order in h[nbnd][nbnd] and int_p[mx_nd_elt][mx_nd_elt] matrices */
		  h[k] += int_p[row + cl_strd_loc];
	       }
	    }  

     dltp2 = dlt*dlt;

     for (k=0; k<3; k++) /* Loop over the sides of element Q */
     {

	 if (k==0) /* if side1: y2-y1, y3-y1 */
	 {
	     qqLoc[0] = 0; qqLoc[1] = 1; qqLoc[2] = 2; /* qqLoc[] = {0,1,2} */
	     pr[0] = xv[0]; /* qr1 = zv[0] = 0.0, By construction qr1 is always equal to zero */
	     pr[1] = xv[2]; qr2 = zv[2];
	     rh2 = rhoSD[1]; rh3 = rhoSD[2];
         }
	 else if(k==1) /* if side2: y3-y2, y1-y2 */
	 {
	     qqLoc[0] = 1; qqLoc[1] = 2; qqLoc[2] = 0; /* qqLoc[] = {1,2,0} */
	     calpk = cos(alpha2); salpk = sin(alpha2);
	     pr[0] = calpk*xv[1] + salpk*zv[1]; /* qr1 = calpk*zv[1] - salpk*xv[1] = 0.0, By construction qr1 is always equal to zero */
	     pr[1] = -calpk*xv[0]; qr2 =  salpk*xv[0];
	     rh2 = rhoSD[2]; rh3 = rhoSD[0];
         }
	 else /* side3: y1-y3, y2-y3 */
	 {
	     qqLoc[0] = 2; qqLoc[1] = 0; qqLoc[2] = 1; /* qqLoc[] = {2,0,1} */
	     calpk = cos(alpha3); salpk = sin(alpha3);
	     pr[0] = -calpk*xv[2] - salpk*zv[2]; /* qr1 = salpk*xv[2] - calpk*zv[2] = 0.0, By construction qr1 is always equal to zero */
	     pr[1] = -calpk*xv[1] - salpk*zv[1]; qr2 =  salpk*xv[1] - calpk*zv[1];
	     rh2 = rhoSD[0]; rh3 = rhoSD[1];
         }
		   
	  a = qr2; b = pr[0]; c = pr[1];
	  ap2 = a*a; bp2 = b*b;
	  
	  rh2p2 = rh2*rh2;   rh3p2 = rh3*rh3;
	  rh2p3 = rh2p2*rh2; rh3p3 = rh3p2*rh3;
	  rh2p4 = rh2p3*rh2; rh3p4 = rh3p3*rh3;
	  
	  bmc = b-c; bc = b*c;
	  bbmc = bp2-bc;
	  bbmc_rh2 = bbmc/rh2; bc_rh3 = bc/rh3;

	  aab = ap2*b;
	  aab_12 = aab/12.0; aab_60 = aab/60.0;

	  rh3_rh2p2 = rh3/rh2p2; rh2_rh3p2 = rh2/rh3p2;
	  
	  
	  dltp2_rh2p2 = dltp2/rh2p2; dltp2_rh3p2 = dltp2/rh3p2;
	  ccf2_75 = 7.5*dltp2_rh2p2; ccf3_75 = 7.5*dltp2_rh3p2;
	  ccf2_15 = 1.5*dltp2_rh2p2; ccf3_15 = 1.5*dltp2_rh3p2;
	  
	  ln1 = log( (rh2 + bmc)/(rh3 - c) );
	  ln2 = log( (b - bbmc_rh2)/(rh2 + rh3 - bbmc_rh2) );
	  ln3 = log( (b - bc_rh3  )/(rh2 + rh3 - bc_rh3  ) );
	  
	  ln2_rh2p3 = ln2/rh2p3; ln3_rh3p3 = ln3/rh3p3;
	  

/* intK(1,1) */
	  intK1 = aab_60*( b*( rh3_rh2p2 + rh2_rh3p2*( 3.0 + (5.5*bp2 - 9.5*bc - ccf3_75)/rh3p2 ) ) + ln1 +
	          bp2*( ( (ccf3_75 + 12.0*bc - 5.5*bp2)/rh3p4 - 6.0/rh3p2 - 1.0/rh2p2 ) - bmc*ln2_rh2p3 + 
	              ( (ccf3_75*c - 3.0*b*(4.0*ap2 + bc))/rh3p2 + 2.0*(4.0*b - 3.0*c) )*ln3_rh3p3 )  );

/* intK(2,2) */
	  intK2 = aab_60*( b*( rh2_rh3p2 + rh3_rh2p2*( 3.0 - (4.0*bp2 - 9.5*bc + ccf2_75)/rh2p2 ) ) + ln1 +
	          bp2*( ( (ccf2_75 + 6.5*bp2 - 12.0*bc)/rh2p4 - 6.0/rh2p2 - 1.0/rh3p2 ) - c*ln3_rh3p3 +
	              ( (ccf2_75*bmc - 3.0*b*(4.0*ap2 + bbmc))/rh2p2 + 2.0*(b + 3.0*c) )*ln2_rh2p3 ) );

/* intK(3,3) */
	  intK3 = aab_60*( 3.0*ln1 + b*( rh3_rh2p2*( 1.0 + (8.0*bp2 - 2.5*bc - ccf2_75)/rh2p2 )   +
	                                 rh2_rh3p2*( 1.0 + (5.5*bp2 + 2.5*bc - ccf3_75)/rh3p2 ) ) +
	          bp2*( ( ccf2_75 - 5.5*bp2 + bmc*(ccf2_75 - 3.0*bp2)*ln2/rh2 )/rh2p4 +
	                ( ccf3_75 - 5.5*bp2 +   c*(ccf3_75 - 3.0*bp2)*ln3/rh3 )/rh3p4 ) );

/* intK(1,2) */
	  intK12 = aab_60*( b*( rh3_rh2p2*(1.0 - 1.5*bbmc/rh2p2) + rh2_rh3p2*(1.0 - 1.5*bc/rh3p2) -
	           (ccf2_15 + 0.5*bp2 - 1.5*bc)*ln2_rh2p3 - (ccf3_15 - bp2 + 1.5*bc)*ln3_rh3p3 ) +
	           0.5*ln1 + bp2*( 1.5*bbmc/rh2p4 - 1.5/rh2p2 + 1.5*bc/rh3p4 - 1.5/rh3p2 ) );

/* intK(1,3) */
	  intK13 = aab_60*( ln1 - bp2*( (ccf3_75 + 6.0*bc - 5.5*bp2)/rh3p4 + 1.5*bbmc/rh2p4 ) +
	           b*( rh3_rh2p2*(0.5 + 1.5*bbmc/rh2p2) + rh2_rh3p2*(1.0 + (3.5*bc - 5.5*bp2 + ccf3_75)/rh3p2) +
	           (ccf2_15 - bp2)*ln2_rh2p3 - ( (ccf3_75*bc - 3.0*bp2*(2.0*ap2 + bc))/rh3p2 + 4.0*bp2 )*ln3_rh3p3 ) );

/* intK(2,3) */
	  intK23 = aab_60*( b*( rh3_rh2p2*(1.0 + (ccf2_75 - 2.0*bp2 - 3.5*bc)/rh2p2) + rh2_rh3p2*(0.5 + 1.5*bc/rh3p2) +
	           (ccf3_15 - bp2)*ln3_rh3p3 - ( (ccf2_75*bbmc - 3.0*bp2*(2.0*ap2 + bbmc))/rh2p2 + 4.0*bp2)*ln2_rh2p3 ) +
	           ln1 - bp2*( (ccf2_75 + 0.5*bp2 - 6.0*bc)/rh2p4 + 1.5*bc/rh3p4 ) );

          intK[0] = intK1;  intK[1] = intK12; intK[2] = intK13; /* intK(1,1) = intK1;  intK(2,1) = intK12; intK(3,1) = intK13 */
	  intK[3] = intK12; intK[4] = intK2;  intK[5] = intK23; /* intK(1,2) = intK12; intK(2,2) = intK2;  intK(3,2) = intK23 */
	  intK[6] = intK13; intK[7] = intK23; intK[8] = intK3;  /* intK(1,3) = intK13; intK(2,3) = intK23; intK(3,3) = intK3  */


         Irhoz = aab_12*( rh3 - rh2 + rh3_rh2p2*(ccf2_15 - bp2 + 0.5*bc) - rh2_rh3p2*(ccf3_15 - 0.5*(bp2+bc)) +
                 b*( (0.5*bp2 - ccf2_15*(1.0 + bmc*ln2/rh2))/rh2p2 - ( 0.5*bp2 - ccf3_15*(1.0 + c*ln3/rh3))/rh3p2 ) );

         Irhoxz = aab_12*( c*(0.6*(rh3-rh2) + bc*ccf3_15*bc_rh3*ln3/rh3p4) + b*(0.4*rh3 -
                  rh2_rh3p2*(0.2*ap2 - 0.3*(bp2+bc) + (0.5*(4.0*dltp2 + aab*c) - ap2*ccf3_15)/rh3p2) -
                  rh3_rh2p2*(0.2*(ap2 + bp2 + bp2 - bc) + (dltp2 - 0.5*aab*c - ap2*ccf2_15)/rh2p2) ) +
                  bp2*((0.2*bp2 + 0.5*dltp2_rh2p2 - ap2*ccf2_15/rh2p2)/rh2p2 -
                  (0.3*bp2 - 2.0*dltp2_rh3p2 + ap2*ccf3_15/rh3p2)/rh3p2) - aab*ccf2_15*bbmc_rh2*ln2/rh2p4 );

         Irhozz = aab_12*( 0.6*a*(rh3-rh2) + dlt*(rh3_rh2p2*((bmc*ccf2_15 + b*(0.5*ap2 - 0.2*bbmc))/rh2p2 - 0.2*(b+bmc)) -
                  rh2_rh3p2*( (c*ccf3_15 + (0.5*aab - 0.2*b*bc))/rh3p2 - 0.2*(b+c) ) +
                  bc_rh3*(ccf3_15 - 0.2*bp2)/rh3p3 - bbmc_rh2*(ccf2_15 - 0.2*bp2)/rh2p3 ) +
                  a*(dltp2_rh2p2*(ccf2_15 - 1.2*bp2)*ln2_rh2p3 - dltp2_rh3p2*(ccf3_15 - 1.2*bp2)*ln3_rh3p3) );

          Ichizz = a*aab_12*( b*(1.5*b*(bbmc_rh2/rh2p3 + bc_rh3/rh3p3) - rh3_rh2p2*(0.5 + 1.5*bbmc_rh2/rh2) -
                  rh2_rh3p2*(0.5 + 1.5*bc_rh3/rh3) + (bp2-ccf2_15)*ln2_rh2p3 + (bp2-ccf3_15)*ln3_rh3p3) - ln1 );

          Ichixzz = a*aab_60*( rh3_rh2p2*( 1.5*bp2 - bc - ( bp2*(2.5*ap2 + 0.5*bbmc) + ccf2_75*bbmc )/rh2p2 ) -
                   rh2_rh3p2*( 3.0*bp2 + bc - ( bp2*(2.5*ap2 - 7.0*bc) + ccf3_75*bc )/rh3p2 ) +
                   b*( bbmc_rh2*(0.5*bp2 + ccf2_75)/rh2p3 + bc_rh3*(7.0*bp2 - ccf3_75)/rh3p3 ) - (b + 3.0*c)*ln1 +
                   bp2*((bp2+ap2*(4.5*bp2 - ccf2_75)/rh2p2)*ln2_rh2p3 + (4.0*bp2 - ap2*(12.0*bp2 - ccf3_75)/rh3p2)*ln3_rh3p3) );

          Ichizzz = -intK3*ap2;

          k2 = -bmc/a; k3 = c/a; c_b = c/b;


	  intN[2] =  0.5*(Irhozz + k2*Ichizzz)/dlt; /* intN(3,1) */
	  intN[1] =  0.5*(Irhoxz + k2*Ichixzz)/bp2 - c_b*intN[2]; /* intN(2,1) */
	  intN[0] =  0.5*(Irhoz  + k2*Ichizz )/b - intN[1] - intN[2]; /* intN(1,1) */

          intN[5] = -0.5*(Irhozz + k3*Ichizzz)/dlt; /* intN(3,2) */
	  intN[4] = -0.5*(Irhoxz + k3*Ichixzz)/bp2 - c_b*intN[5]; /* intN(2,2) */
	  intN[3] = -0.5*(Irhoz  + k3*Ichizz )/b - intN[4] - intN[5]; /* intN(1,2) */

          intN[8] = -(intN[2]+intN[5]); /* intN(3,3) */
	  intN[7] = -(intN[1]+intN[4]); /* intN(2,3) */
	  intN[6] = -(intN[0]+intN[3]); /* intN(1,3) */

	  for (col=0; col<mx_nd_elt; col++)
	  {
	     cl_strd_loc = mx_nd_elt*col; /* cl_strd_loc == Local Column stride */
	     j=mx_nd_elt*qqLoc[col]; /* j == Local Column stride */
	     for (row=0; row<mx_nd_elt; row++) /* Column-major order in int_f, intK and intN matrices */
	        int_f[qqLoc[row] + j] += intK[row + cl_strd_loc] + intN[row + cl_strd_loc];
	  }
     } /* Loop over the sides of element Q */

    for (col=0; col<mx_nd_elt; col++)
    {
       cl_strd_loc = mx_nd_elt*col; /* cl_strd_loc == Local Column stride */
       cl_strd = nbnd*qq[col]; /* cl_strd == Column stride */
       for (row=0; row<mx_nd_elt; row++)
	  {
	     k=pp[row] + cl_strd; /* Column-major order in g[nbnd][nbnd] and int_f[mx_nd_elt][mx_nd_elt] matrices */
	     g[k] += int_f[row + cl_strd_loc];
	  }
    }

}
