#include <math.h>
#include "cbem_util.h"


void cbem_lap_ex_int_ud(int elQ)
{

/* ===purpose=== */

/**********************************************************************************************************************************/
/********************************  COLLOCATION BEM for 3D LAPLACE EQUATION: SINGULAR FORMULATION  *********************************/
/***************************************  3-NODED TRIANGULAR ELEMENT: ANALYTIC INTEGRATION  ***************************************/
/***********************************************  PIECEWISE CONSTANT APPROXIMATION  ***********************************************/
/********************************  EXact INTegration with Uniform Distribution on a flat triangle  ********************************/
/*******  Given the boundary element elQ, Assemble the influence contribution to all collocation points in h and g matrices  ******/
/**********************************************************************************************************************************/

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


/* typical triangular element with vertices {y1,y2,y3}

*           y3
*	    *
*	   / \
*	  /   \
*	 /     \
*       /       \
*      /	 \
*     /		  \
*    *-------------*
*  y1               y2

* Oriented edge L1 = [y1,y2] <== Edge1
* Oriented edge L2 = [y2,y3] <== Edge2
* Oriented edge L3 = [y3,y1] <== Edge3
*/
 

/* Note: elQ == Global index of the current boundary element */
   extern const int mx_nd_elt; /* mx_nd_elt == Maximum number of nodes per element */
   extern int nbelt;           /* nbelt == Total number of boundary elements */
   extern int **belt;          /* belt[elQ][k] == Global index of the k-th node on the boundary element elQ */
   extern double pi;           /* pi = 3.1415926535897932 */
   extern double gm_eps,f_eps; /* gm_eps == Tolerance on the geometry */
                               /* f_eps == Tolerance on the argument of a function */
   extern double **bnd;        /* bnd[k][0:2] == Cartesian coordinates of the k-th boundary node */
   extern double **repnd;      /* repnd[i][0:2] == Cartesian coordinates of the centroid of the i-th boundary triangle */
   extern double *h,*g;        /* h == potential influence matrix, g == flux influence matrix */

   int k,i,th_id,cl_stride;
   double e1[3],e2[3],e3[3]; /* Orthonormal companion basis associated with element elQ */
   double xeQ[mx_nd_elt][3]; /* xeQ[k][0:2] == Cartesian coordinates of the k-th vertex of the triangle elQ */
   double aQ,bQ,cQ; /* Geometric parameters of element elQ: bQ = base, aQ = height, */
                    /* cQ = relative position of the 3rd node of element elQ        */
   double r1[3],xi,zt,eth,et,ets,q[3],qs[3],rho[3],chi[3],gamma[3],gam;
   double vij[2][3],aQs,bmc,theta[3],alpha2,alpha3,Rh[3],Rhs[3],ch11,ch12,ch22,ch23,ch33,ch31;
   double kQ3; /* kQ3 == Slope of Edge3 of element elQ */
   double shc[mx_nd_elt],sncf2,sncf3,cscf2,cscf3,qetx2[3];
   double p11,p12,p22,p23,p33,p31,x3,z3,rh1s,rh2s,rh3s,p11s,p12s,p33s,p11rh1,p31rh1,omega;
   double cr11,cr12,zn1,zd1,cr22,cr23,zn2,zd2,cr31,cr33,zn3,zd3,p12rh2,p22rh2,p23rh3,p33rh3,theta0,ThetGam;
/* Note: Below, the Projection of the collocation point repnd[i][0:2] means the Projection of the collocation point repnd[i][0:2] on
 * Note: the plane of element elQ in the direction e3. e3 is the unit normal to element elQ */

/* pt_tria_tst, gammai, asym_chi are external functions (see cbem_util.c) */



    cl_stride = nbelt*elQ; /* cl_stride == Column stride */
    
    for (k=0; k<mx_nd_elt; k++) /* Loop over all vertices of element elQ */
       for (i=0; i<3; i++)      /* Loop over all components */
          xeQ[k][i] = bnd[belt[elQ][k]][i]; /* xeQ[k][0:2] == Cartesian coordinates of the k-th vertex on the triangle elQ */
	                                    /* belt[elQ][k] == Global index of the k-th node on the boundary element elQ   */

    for (k=0; k<3; k++) /* Loop over all components */
    {
       vij[0][k] = xeQ[1][k] - xeQ[0][k]; /* y2-y1 <== Side 1 of element elQ */
       vij[1][k] = xeQ[2][k] - xeQ[0][k]; /* y3-y1 <== Side 3 of element elQ */
    }

    ortho_comp_basis(vij[0],vij[1],e1,e2,e3); /* Deternime the orthonormal companion basis associated with element elQ */
       
    bQ = vij[0][0]*e1[0] + vij[0][1]*e1[1] + vij[0][2]*e1[2]; /* bQ>0.0 always */
    aQ = vij[1][0]*e2[0] + vij[1][1]*e2[1] + vij[1][2]*e2[2]; /* aQ>0.0 always */
    cQ = vij[1][0]*e1[0] + vij[1][1]*e1[1] + vij[1][2]*e1[2];

    bmc = bQ-cQ; aQs = aQ*aQ;

    theta[0] = acos(cQ/sqrt(cQ*cQ + aQs)); theta[1] = acos(bmc/sqrt(bmc*bmc + aQs)); theta[2] = pi - (theta[0]+theta[1]);

    alpha2 = pi-theta[1]; alpha3 = pi+theta[0]; /* alpha1 = 0.0 */

/*    kQ2 = -bmc/aQ;  kQ2 == Slope of Side 2 of element elQ */
    kQ3 = cQ/aQ; /* kQ3 == Slope of Side 3 of element elQ */

    cscf2 = cos(alpha2); sncf2 = sin(alpha2); cscf3 = cos(alpha3); sncf3 = sin(alpha3);
     
    for (i=0; i<nbelt; i++) /* Loop over all representative nodes (collocation points) on the boundary */
    {
	for (k=0; k<3; k++) /* Loop over all components */
	   r1[k] = repnd[i][k] - xeQ[0][k]; /* r1 = repnd[i][0:2]-y1 */

         xi = r1[0]*e1[0] + r1[1]*e1[1] + r1[2]*e1[2];
	 zt = r1[0]*e2[0] + r1[1]*e2[1] + r1[2]*e2[2];
	eth = r1[0]*e3[0] + r1[1]*e3[1] + r1[2]*e3[2];
	   
        p11 = -xi; p12 = bQ-xi; q[0] = -zt; et = -eth;

	if (fabs(et) < gm_eps) et = 0.0;

	x3 = cQ+p11; z3 = aQ+q[0];
	p22 = p12*cscf2 + q[0]*sncf2; p23 = x3*cscf2 + z3*sncf2; q[1] = q[0]*cscf2 - p12*sncf2;
	p31 = p11*cscf3 + q[0]*sncf3; p33 = x3*cscf3 + z3*sncf3; q[2] = q[0]*cscf3 - p11*sncf3;

	ets = et*et; p11s = p11*p11; p12s = p12*p12; p33s = p33*p33; qs[0] = q[0]*q[0]; qs[1] = q[1]*q[1]; qs[2] = q[2]*q[2];

	Rhs[0] = p11s + qs[0]; Rhs[1] = p12s + qs[0]; Rhs[2] = p33s + qs[2]; /* Rhs(3) = x3*x3 + z3*z3 */
	Rh[0] = sqrt(Rhs[0]); Rh[1] = sqrt(Rhs[1]); Rh[2] = sqrt(Rhs[2]);
	rh1s = Rhs[0] + ets; rh2s = Rhs[1] + ets; rh3s = Rhs[2] + ets;
	rho[0] = sqrt(rh1s); rho[1] = sqrt(rh2s); rho[2] = sqrt(rh3s);

	shc[2] = -q[0]/aQ; shc[1] = (kQ3*q[0] - p11)/bQ;
	shc[0] = 1.0 - (shc[2]+shc[1]); /* shc[0] = 1.0 + (p11 - kQ2*q[0])/bQ */

	   if ( fabs(shc[0]) < gm_eps ) { shc[0] = 0.0; q[1] = 0.0; }
	   
	   if ( fabs(shc[1]) < gm_eps ) { shc[1] = 0.0; q[2] = 0.0; }
	   else if ( fabs(shc[1]-1.0) < gm_eps ) shc[1] = 1.0;
	   
	   if ( fabs(shc[2]) < gm_eps ) { shc[2] = 0.0; q[0] = 0.0; }
	   else if ( fabs(shc[2]-1.0) < gm_eps ) shc[2] = 1.0;

	   theta0 = pt_tria_tst(shc[0],shc[1],shc[2],theta,&th_id); /* Point in triangle test */
	   
	   if ( th_id == 4 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y1 */
	   {
	       Rh[0] = 0.0;
	       if (et == 0.0) rho[0] = 0.0; /* repnd[i][0:2] = y1 */
	   }
	   else if ( th_id == 5 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y2 */
	   {
	       Rh[1] = 0.0;
	       if (et == 0.0) rho[1] = 0.0; /* repnd[i][0:2] = y2 */
	   }
	   else if ( th_id == 6 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y3 */
	   {
	      Rh[2] = 0.0;
	      if (et == 0.0) rho[2] = 0.0; /* repnd[i][0:2] = y3 */
	   }

	   qetx2[0] = 2.0*q[0]*et; qetx2[1] = 2.0*q[1]*et; qetx2[2] = 2.0*q[2]*et;

	   p11rh1 = p11*rho[0]; p12rh2 = p12*rho[1];
	   p22rh2 = p22*rho[1]; p23rh3 = p23*rho[2];
	   p33rh3 = p33*rho[2]; p31rh1 = p31*rho[0];

	  if ( i == elQ ) /* repnd[i][0:2] = repnd[elQ][0:2] <==> element self-interaction */
	  {
	    gam = 0.0;
	    omega = q[0]*log((p11+rho[0])/(p12+rho[1]))+q[1]*log((p22+rho[1])/(p23+rho[2]))+q[2]*log((p33+rho[2])/(p31+rho[0]));
	  }
	  else if ( rho[0] == 0.0 ) /* if The collocation point repnd[i][0:2] is at vertex y1, i.e., repnd[i][0:2] = xeQ[0][0:2] */
	  {
	    gam = 0.0;
	    omega = q[1]*log( (p22+rho[1])/(p23+rho[2]) ); /* chi[1] = log( (p22+rho[1])/(p23+rho[2]) ) */
	  }
	  else if ( rho[1] == 0.0 ) /* if The collocation point repnd[i][0:2] is at vertex y2, i.e., repnd[i][0:2] = xeQ[1][0:2] */
	  {
	    gam = 0.0;
	    omega = q[2]*log( (p33+rho[2])/(p31+rho[0]) ); /* chi[2] = log( (p33+rho[2])/(p31+rho[0]) ) */
	  }
	  else if ( rho[2] == 0.0 ) /* if The collocation point repnd[i][0:2] is at vertex y3, i.e., repnd[i][0:2] = xeQ[2][0:2] */
	  {
	    gam = 0.0;
	    omega = q[0]*log( (p11+rho[0])/(p12+rho[1]) ); /* chi[0] = log( (p11+rho[0])/(p12+rho[1]) ) */
	  }
	  else
	  {
                      if ( Rh[0] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y1 */
		      {
	                    cr22 = qs[1]*rh2s-p22*p22*ets; cr23 = qs[1]*rh3s-p23*p23*ets;
	                    zn2 = qetx2[1]*(p23rh3*cr22 - p22rh2*cr23); zd2 = cr22*cr23 + qetx2[1]*qetx2[1]*p22rh2*p23rh3;
		            gam = gammai(p22,p23,qetx2[1],cr22,cr23,zn2,zd2); /* gam = gamma[1]; gamma[0] = -gamma[2] = +pi or -pi */
	              }
		      else if ( Rh[1] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y2 */
		      {
	                    cr33 = qs[2]*rh3s - p33s*ets; cr31 = qs[2]*rh1s - p31*p31*ets;
	                    zn3 = qetx2[2]*(p31rh1*cr33 - p33rh3*cr31); zd3 = cr31*cr33 + qetx2[2]*qetx2[2]*p31rh1*p33rh3;
	                    gam = gammai(p33,p31,qetx2[2],cr33,cr31,zn3,zd3); /* gam = gamma[2]; gamma[0] = -gamma[1] = +pi or -pi */
	              }
		      else if ( Rh[2] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is at vertex y3 */
		      {
	                    cr11 = qs[0]*rh1s - p11s*ets; cr12 = qs[0]*rh2s - p12s*ets;
	                    zn1 = qetx2[0]*(p12rh2*cr11 - p11rh1*cr12); zd1 = cr11*cr12 + qetx2[0]*qetx2[0]*p11rh1*p12rh2;
	                    gam = gammai(p11,p12,qetx2[0],cr11,cr12,zn1,zd1); /* gam = gamma[0]; gamma[1] = -gamma[2] = +pi or -pi */
	              }
		      else if ( q[0] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is on the line parallel to edge [y1,y2] */
		      {
	                    cr22 = qs[1]*rh2s-p22*p22*ets; cr23 = qs[1]*rh3s-p23*p23*ets;
	                    zn2 = qetx2[1]*(p23rh3*cr22 - p22rh2*cr23); zd2 = cr22*cr23 + qetx2[1]*qetx2[1]*p22rh2*p23rh3;

	                    cr33 = qs[2]*rh3s - p33s*ets; cr31 = qs[2]*rh1s - p31*p31*ets;
	                    zn3 = qetx2[2]*(p31rh1*cr33 - p33rh3*cr31); zd3 = cr31*cr33 + qetx2[2]*qetx2[2]*p31rh1*p33rh3;
		 
	                    gamma[1] = gammai(p22,p23,qetx2[1],cr22,cr23,zn2,zd2);
	                    gamma[2] = gammai(p33,p31,qetx2[2],cr33,cr31,zn3,zd3);
		            gam = gamma[1]+gamma[2];
	              }
		      else if ( q[1] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is on the line parallel to edge [y2,y3] */
		      {
	                    cr11 = qs[0]*rh1s - p11s*ets; cr12 = qs[0]*rh2s - p12s*ets;
	                    zn1 = qetx2[0]*(p12rh2*cr11 - p11rh1*cr12); zd1 = cr11*cr12 + qetx2[0]*qetx2[0]*p11rh1*p12rh2;

	                    cr33 = qs[2]*rh3s - p33s*ets; cr31 = qs[2]*rh1s - p31*p31*ets;
	                    zn3 = qetx2[2]*(p31rh1*cr33 - p33rh3*cr31); zd3 = cr31*cr33 + qetx2[2]*qetx2[2]*p31rh1*p33rh3;
		 
		            gamma[0] = gammai(p11,p12,qetx2[0],cr11,cr12,zn1,zd1);
	                    gamma[2] = gammai(p33,p31,qetx2[2],cr33,cr31,zn3,zd3);
		            gam = gamma[0]+gamma[2];
	              }
		      else if ( q[2] == 0.0 ) /* if the Projection of the collocation point repnd[i][0:2] is on the line parallel to edge [y3,y1] */
		      {
	                    cr11 = qs[0]*rh1s - p11s*ets; cr12 = qs[0]*rh2s - p12s*ets;
	                    zn1 = qetx2[0]*(p12rh2*cr11 - p11rh1*cr12); zd1 = cr11*cr12 + qetx2[0]*qetx2[0]*p11rh1*p12rh2;

	                    cr22 = qs[1]*rh2s-p22*p22*ets; cr23 = qs[1]*rh3s-p23*p23*ets;
	                    zn2 = qetx2[1]*(p23rh3*cr22 - p22rh2*cr23); zd2 = cr22*cr23 + qetx2[1]*qetx2[1]*p22rh2*p23rh3;
		 
		            gamma[0] = gammai(p11,p12,qetx2[0],cr11,cr12,zn1,zd1);
	                    gamma[1] = gammai(p22,p23,qetx2[1],cr22,cr23,zn2,zd2);
		            gam = gamma[0]+gamma[1];
	              }
		      else 
		      {    
		            cr11 = qs[0]*rh1s - p11s*ets; cr12 = qs[0]*rh2s - p12s*ets;
	                    zn1 = qetx2[0]*(p12rh2*cr11 - p11rh1*cr12); zd1 = cr11*cr12 + qetx2[0]*qetx2[0]*p11rh1*p12rh2;

	                    cr22 = qs[1]*rh2s-p22*p22*ets; cr23 = qs[1]*rh3s-p23*p23*ets;
	                    zn2 = qetx2[1]*(p23rh3*cr22 - p22rh2*cr23); zd2 = cr22*cr23 + qetx2[1]*qetx2[1]*p22rh2*p23rh3;

	                    cr33 = qs[2]*rh3s - p33s*ets; cr31 = qs[2]*rh1s - p31*p31*ets;
	                    zn3 = qetx2[2]*(p31rh1*cr33 - p33rh3*cr31); zd3 = cr31*cr33 + qetx2[2]*qetx2[2]*p31rh1*p33rh3;
		 
		            gamma[0] = gammai(p11,p12,qetx2[0],cr11,cr12,zn1,zd1);
	                    gamma[1] = gammai(p22,p23,qetx2[1],cr22,cr23,zn2,zd2);
	                    gamma[2] = gammai(p33,p31,qetx2[2],cr33,cr31,zn3,zd3);
		            gam = gamma[0]+gamma[1]+gamma[2];
		      }


		   ch11 = p11+rho[0]; ch12 = p12+rho[1];
		   ch22 = p22+rho[1]; ch23 = p23+rho[2];
		   ch33 = p33+rho[2]; ch31 = p31+rho[0];

		   if ( (ch11 >= f_eps) && (ch12 >= f_eps) )
		      chi[0] = log(ch11/ch12);
		   else
		      chi[0] = asym_chi(p11,p12,qs[0] + ets);

		   if ( (ch22 >= f_eps) && (ch23 >= f_eps) )
		      chi[1] = log(ch22/ch23);
		   else
		      chi[1] = asym_chi(p22,p23,qs[1] + ets);

		   if ( (ch33 >= f_eps) && (ch31 >= f_eps) )
		      chi[2] = log(ch33/ch31);
		   else
		      chi[2] = asym_chi(p33,p31,qs[2] + ets);

		   omega = q[0]*chi[0] + q[1]*chi[1] + q[2]*chi[2];

	  }

	if ( et > 0.0 )
	   ThetGam = 0.5*gam + theta0;
	else
	   ThetGam = 0.5*gam - theta0;
	
	k = i+cl_stride; /* Column-major order in h and g matrices: cl_stride = nbelt*elQ */
	h[k] = -ThetGam;
	g[k] =  omega - et*ThetGam;
    } /* End Loop over all representative nodes (collocation points) on the boundary */

}
