// BemSolveDoc.cpp : implementation of the CBemSolveDoc class
//

#include "stdafx.h"
#include "math.h"
#include "BemSolve.h"

#include "geom.h"
#include "BemSolveDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBemSolveDoc

IMPLEMENT_DYNCREATE(CBemSolveDoc, CDocument)

BEGIN_MESSAGE_MAP(CBemSolveDoc, CDocument)
	//{{AFX_MSG_MAP(CBemSolveDoc)
	ON_COMMAND(ID_SOLVE_EQU, OnSolveEqu)
	ON_COMMAND(ID_SOLVE_INT, OnSolveInt)
	ON_COMMAND(ID_SOLVE_WELL, OnSolveWell)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBemSolveDoc construction/destruction

CBemSolveDoc::CBemSolveDoc()
{
	res=h=g=drs=NULL;
}

CBemSolveDoc::~CBemSolveDoc()
{
}

BOOL CBemSolveDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;
	memset (&lfnt,0,sizeof(LOGFONT));
	lfnt.lfHeight=-12;
	strcpy (lfnt.lfFaceName,"Courier New");
	bounl=bounr=bount=bounb=720;

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CBemSolveDoc serialization

void CBemSolveDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		ar << name << kx << ky << thick;
		ar.Write (&lfnt,sizeof(LOGFONT));
	}
	else
	{
		ar >> name >> kx >> ky >> thick;
		ar.Read (&lfnt,sizeof(LOGFONT));
	}
	Nodes.Serialize(ar);
	Elems.Serialize(ar);
	Wells.Serialize(ar);
	IntNods.Serialize(ar);
	TriElems.Serialize(ar);
}

/////////////////////////////////////////////////////////////////////////////
// CBemSolveDoc diagnostics

#ifdef _DEBUG
void CBemSolveDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CBemSolveDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CBemSolveDoc commands

void CBemSolveDoc::DeleteContents() 
{
	int i=0;
	while (i<Nodes.GetSize())
	{
		delete Nodes.GetAt(i++);
	}	                     
	Nodes.RemoveAll();
	i=0;
	while (i<Elems.GetSize())
	{
		delete Elems.GetAt(i++);
	}	                     
	Elems.RemoveAll();
	i=0;
	while (i<Wells.GetSize())
	{
		delete Wells.GetAt(i++);
	}	                     
	Wells.RemoveAll();
	i=0;
	while (i<IntNods.GetSize())
	{
		delete IntNods.GetAt(i++);
	}	                     
	IntNods.RemoveAll();
	i=0;
	while (i<TriElems.GetSize())
	{
		delete TriElems.GetAt(i++);
	}	                     
	TriElems.RemoveAll();
	
	if (drs) delete drs;
	if (h) delete h;
	if (g) delete g;
	if (res) delete res;
	CDocument::DeleteContents();
}

BOOL CBemSolveDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
	if (!CDocument::OnOpenDocument(lpszPathName))
		return FALSE;
	
	int nel=Elems.GetSize();
	long ij=nel*nel;
	drs=new double[nel];res=new double[nel];
	h=new double[ij];g=new double[ij];
	lfntw=lfnt;lfntw.lfHeight=20*lfnt.lfHeight;
	strcpy (lfntw.lfFaceName,"Courier New");
	
 	tx=kx*thick;ty=ky*thick;
	tt=sqrt(ty/tx);
	txy=sqrt(tx/ty);
	rprec=precip/(tx*3.1536e10);     // from mm/year to m3/sec

	return TRUE;
}

CNode* CBemSolveDoc::GetNode(int i)
{
	return (CNode*)Nodes.GetAt(i);
}

CElement* CBemSolveDoc::GetElement(int i)
{
	return (CElement*)Elems.GetAt(i);
}

CIntPoint* CBemSolveDoc::GetIntPt(int i)
{
	return (CIntPoint*)IntNods.GetAt(i);
}

CIntElem* CBemSolveDoc::GetIntElm(int i)
{
	return (CIntElem*)TriElems.GetAt(i);
}

CWell* CBemSolveDoc::GetWell(int i)
{
	return (CWell*)Wells.GetAt(i);
}

void CBemSolveDoc::Assemble() 
{
	int nel,ntrid,nwl,i,j,i1,i2;
	long ii,ij;
	double xm,ym,*dl,hh,hp,gp,qin,x1,y1,x2,y2,
		sumpr,sx,sy,dx,dy,qq,ra,ch;
	
	nel=Elems.GetSize();
	ntrid=TriElems.GetSize();
	nwl=Wells.GetSize();
	
	dl=new double[nel];
 	for (i=0;i<nel;i++) dl[i]=drs[i]=0.0;
 	for (i=0;i<nel;i++)
 	{
  		CElement* el=GetElement(i);
		for (j=0;j<nel;j++)
		{
			ij=ind(i,j,nel);
			h[ij]=g[ij]=0.0;
		}

  		switch (el->type)
  		{
  		case 1:
    		dl[i]=el->pot;
			break;
   		case 2:
    		dl[i]=el->der;
			break;
   		case 3:
			qin=el->kf0/(el->dist*tx);
			dl[i]=qin*el->level;
			drs[i]=qin;
			break;
		}
	}

/******** Integration and assembling h,g ***/

	for (i=0;i<nel;i++)
 	{
  		CElement* el=GetElement(i);
		i1=el->nod1;i2=el->nod2;
		CNode* nd1=GetNode(i1);CNode* nd2=GetNode(i2);
		xm=(nd1->xb+nd2->xb)*0.5;ym=(nd1->yb+nd2->yb)*0.5*txy;
  		hh=0.0;
  		for (j=0;j<nel;j++)
  		{
  			CElement* elj=GetElement(j);
			i1=elj->nod1;i2=elj->nod2;
			CNode* ndj1=GetNode(i1);CNode* ndj2=GetNode(i2);
			x1=ndj1->xb;y1=ndj1->yb*txy;
			x2=ndj2->xb;y2=ndj2->yb*txy;
   			ij=ind (i,j,nel);
   			Integ (xm,ym,x1,y1,x2,y2,hp,gp,tt,1.0);
   			if(i!=j)
   			{
    			hh=hh+hp;
    			h[ij]=hp+drs[j]*gp;
   			}
   			else
			{
				h[ij]=drs[j]*gp;
			}
   			g[ij]=gp;
  		}
  		h[ind(i,i,nel)]-=hh;
 	}
/**************** changing columns and multiplying by dl *******/
 	for (j=0;j<nel;j++)
 	{
  		CElement* el=GetElement(j);
  		if (el->type>1)
  		{
   			for (i=0;i<nel;i++)
   			{
    			ii=ind (i,j,nel);
    			ch=g[ii];g[ii]=-h[ii];h[ii]=-ch;
   			}
  		}
 	}
	for (i=0;i<nel;i++)
	{
		drs[i]=0.0;
		for (j=0;j<nel;j++)
		{
			ij=ind(i,j,nel);
			drs[i]+=h[ij]*dl[j];
		}
	}
//******** Area integration
 	if (ntrid>0 && precip>0.0)
 	{
  		for (i=0;i<nel;i++)
  		{
  			CElement* el=GetElement(i);
			i1=el->nod1;i2=el->nod2;
			CNode* nd1=GetNode(i1);CNode* nd2=GetNode(i2);
			xm=(nd1->xb+nd2->xb)*0.5;ym=(nd1->yb+nd2->yb)*0.5;
   			sumpr=VnInteg (xm,ym,tt,txy,sx,sy);
   			drs[i]-=sumpr*rprec;
  		}
 	}
/****************** Singular wells *********************/
 	if (nwl>0)
 	{
  		for (i=0;i<nel;i++)
  		{
  			CElement* el=GetElement(i);
			i1=el->nod1;i2=el->nod2;
			CNode* nd1=GetNode(i1);CNode* nd2=GetNode(i2);
			xm=(nd1->xb+nd2->xb)*0.5;ym=(nd1->yb+nd2->yb)*0.5*txy;
   			for (j=0;j<nwl;j++)
   			{   
   				CWell* wl=GetWell(j);
    			dx=xm-wl->xz;dy=ym-wl->yz*txy;
       			qq=wl->yield/tx;
    			ra=1.0/sqrt(dx*dx+dy*dy);
    			drs[i]+=qq*log(ra);
   			}
  		}
 	}
	delete dl;
}

void CBemSolveDoc::OnSolveEqu() 
{
	Assemble();
	SolveEqu();
}

void CBemSolveDoc::SolveEqu() 
{
 	int i,j,iflag,itemp,k,nn,l,ik,ii,is;
 	long i1,i2,i3,i4;
 	int *ip;
 	double d,z1,tx,qin;
	int neq=Elems.GetSize();
 	
 	iflag=1;
 	nn=neq-1;                          
 	ip=new int[neq];
 	for (i=0;i<neq;i++) ip[i]=i;

 	for (k=0;k<nn;k++)
 	{
  		for (i=k+1;i<neq;i++)
  		{
   			i1=ind2(k,ip[k],neq);
   			i2=ind2(k,ip[i],neq);
   			if (fabs(g[i1])>=fabs(g[i2])) continue;
   			itemp=ip[k];ip[k]=ip[i];ip[i]=itemp;
  		}
  		ik=ip[k];
  		i1=ind2(k,ik,neq);
  		d=g[i1];
  		if (fabs(d)<1e-9)
  		{
  			AfxMessageBox ("Singular matrix!");return;
  		}
  		for (i=k+1;i<neq;i++)
  		{
   			ii=ip[i];i2=ind2(k,ii,neq);
   			z1=g[i2];
   			if (fabs(z1)<1e-9) continue;
   			z1=z1/d;
   			for (j=k+1;j<neq;j++)
   			{
    			i3=ind2(j,ik,neq);i4=ind2(j,ii,neq);
    			g[i4]-=z1*g[i3];
   			}
   			drs[ii]-=z1*drs[ik];
  		}
 	}
 	i1=ind2(nn,ip[nn],neq);
 	if (fabs(g[i1])<1e-9)
  	{
  		AfxMessageBox ("Singular matrix!");return;
  	}

 	for (k=nn;k>=0;k--)
  	{
   		ik=ip[k];d=0.0;l=k+1;
   		if (l<neq)
   		{
    		for (j=l;j<neq;j++)
    		{
     			i1=ind2(j,ik,neq);
     			d+=g[i1]*res[j];
    		}
   		}
   		i2=ind2(k,ik,neq);
   		res[k]=drs[ik]=(drs[ik]-d)/g[i2];
 	}
	delete ip;

   	SetModifiedFlag();
  	for (is=0;is<Elems.GetSize();is++)
   	{
   		CElement* el=GetElement(is);
    	switch (el->type)
    	{
     	case 1:
      		el->der=res[is];break;
     	case 2:
      		el->pot=res[is];break;
     	case 3: 
			el->pot=res[is];
			tx=kx*thick;
			qin=el->kf0/(el->dist*tx);
			el->der=qin*(el->level-el->pot);
			break;

    	}
  	}
}

void CBemSolveDoc::OnSolveInt() 
{
	int iv;
  	for (iv=0;iv<IntNods.GetSize();iv++)
  	{
  		CIntPoint* pint=GetIntPt(iv);
  		pint->drwdown=pint->vx=pint->vy=0.0F;
		PointInteg(pint->xz,pint->yz,pint->drwdown,pint->vx,pint->vy);
    	SetModifiedFlag();
   	}
}

void CBemSolveDoc::OnSolveWell() 
{
	float xz,yz,drwd,rds,drt,vx,vy;
	int i;
	for (i=0;i<Wells.GetSize();i++)
	{
		CWell* wl=GetWell(i);
		drwd=0.0f;rds=wl->diam*0.5f;
		xz=wl->xz+rds;yz=wl->yz;
		PointInteg (xz,yz,drt,vx,vy);
		drwd+=drt;
		xz=wl->xz-rds;yz=wl->yz;
		PointInteg (xz,yz,drt,vx,vy);
		drwd+=drt;
		xz=wl->xz;yz=wl->yz+rds;
		PointInteg (xz,yz,drt,vx,vy);
		drwd+=drt;
		xz=wl->xz;yz=wl->yz-rds;
		PointInteg (xz,yz,drt,vx,vy);
		drwd+=drt;
		wl->drwdown=drwd*0.25f;
	}
}

void CBemSolveDoc::PointInteg(float xz, float yz, float &drwd, float &vx, float &vy)
{
	int j,i1,i2;
	double tp,ax,bx,ay,by,sumpr,a,b,sx,sy;
	double x1,x2,y1,y2,dx,dy,rb,qq,ra;
	float yyz=yz*txy;
	int nel=Elems.GetSize();
	int nwl=Wells.GetSize();
	int ntri=TriElems.GetSize();

	tp= 0.1591549430919/tt;       // 1/(2*pi)

	drwd=vx=vy=0.0;
	for (j=0;j<nel;j++)
    {
  		CElement* el=GetElement(j);
		i1=el->nod1;i2=el->nod2;
		CNode* nd1=GetNode(i1);CNode* nd2=GetNode(i2);
		x1=nd1->xb;y1=nd1->yb*txy;x2=nd2->xb;y2=nd2->yb*txy;
    	Integ (xz,yyz,x1,y1,x2,y2,a,b,tt,1.0);
    	InVel (xz,yyz,x1,y1,x2,y2,ax,ay,bx,by,tt,1.0);
    	drwd+=el->der*b-el->pot*a;
    	vx+=el->der*bx-el->pot*ax;
    	vy+=el->der*by-el->pot*ay;
    }
    if (nwl>0)
    {
    	sx=sy=0.0;
    	for (j=0;j<nwl;j++)
    	{             
    		CWell* wl=GetWell(j);
    		dx=xz-wl->xz;dy=(yz-wl->yz)*txy;
      		rb=dx*dx+dy*dy;
       		qq=-wl->yield/tx;
      		ra=1./sqrt(rb);
      		drwd+=qq*log(ra);
      		sx+=qq*dx/rb;sy+=qq*dy/rb;
     	}
     	vx+=sx;vy+=sy;
    }
    if (ntri>0)
    {
     	sumpr=VnInteg (xz,yz,tt,txy,sx,sy);
    	drwd-=sumpr;
		vx+=sx;vy+=sy;
    }
    drwd*=tp;vx*=tp*kx;vy*=tp*ky*txy;
}

long CBemSolveDoc::ind (int i,int j,int nr)
{
 	return ((long)i*(long)nr+(long)j);
}

long CBemSolveDoc::ind2 (int i,int j,int nr)
{
 	return ((long)j*(long)nr+(long)i);
}

int CBemSolveDoc::PrintElem(CDC &td, int iy)
{
	CFont hf,*hfp;
	CString msg;
	hf.CreateFontIndirect(&lfntw);
	int i,i1,i2,iyp;
	float x1,y1,x2,y2,bc;
	iyp=iy;
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	msg="Input data for elements";
	td.TextOut(bounl,iyp,msg);iyp-=2*sz.cy;
	msg="El.no.       1st node          2nd node  b.c.kind  b.c.value";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	msg="---------------------------------------------------------------";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	for (i=0;i<Elems.GetSize();i++)
	{
		CElement* el=GetElement(i);
		i1=el->nod1;i2=el->nod2;
		CNode* nd1=GetNode(i1);CNode* nd2=GetNode(i2);
		x1=nd1->xb;y1=nd1->yb;x2=nd2->xb;y2=nd2->yb;
		if (el->type==1) bc=el->pot;
		else bc=el->der;
		msg.Format("%6d %8.3f %8.3f %8.3f %8.3f  %3d  %8.3f",i+1,x1,y1,x2,y2,el->type,bc);
		td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	}
	td.SelectObject(hfp);
	hf.DeleteObject();
	return iyp;
}

int CBemSolveDoc::PrintElemR(CDC &td, int iy)
{
	CFont hf,*hfp;
	CString msg;
	hf.CreateFontIndirect(&lfntw);
	int i,iyp;
	float dfi,dfsum;
	iyp=iy;
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	msg="Results in elements";
	td.TextOut(bounl,iyp,msg);iyp-=2*sz.cy;
	msg="El.no.   Potential  Derivative   Flux";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	msg="-----------------------------------------------";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	dfsum=0.0f;
	for (i=0;i<Elems.GetSize();i++)
	{
		CElement* el=GetElement(i);
		dfi=Flow(el);dfsum+=dfi;
		msg.Format("%6d %10.4f %10.5f %12.7f",i+1,el->pot,el->der,dfi);
		td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	}
	msg.Format("Total flux=%12.7f",dfsum);
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	td.SelectObject(hfp);
	hf.DeleteObject();
	return iyp;
}

int CBemSolveDoc::PrintWellR(CDC &td, int iy)
{
	CFont hf,*hfp;
	CString msg;
	hf.CreateFontIndirect(&lfntw);
	int i,iyp;
	iyp=iy;
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	msg="Results in wells";
	td.TextOut(bounl,iyp,msg);iyp-=2*sz.cy;
	msg="Well    Diameter   Potential";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	msg="-----------------------------------------------";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	for (i=0;i<Wells.GetSize();i++)
	{
		CWell* wl=GetWell(i);
		msg.Format("   %10.4f %10.5f",wl->diam,wl->drwdown);
		msg=wl->name+msg;
		td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	}
	td.SelectObject(hfp);
	hf.DeleteObject();
	return iyp;
}

int CBemSolveDoc::PrintIntR(CDC &td, int iy)
{
	CFont hf,*hfp;
	CString msg;
	hf.CreateFontIndirect(&lfntw);
	int i,iyp;
	iyp=iy;
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	msg="Results in internal points";
	td.TextOut(bounl,iyp,msg);iyp-=2*sz.cy;
	msg="Point no.   Potential        Vx           Vy";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	msg="---------------------------------------------------";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	for (i=0;i<IntNods.GetSize();i++)
	{
		CIntPoint* ipt=GetIntPt(i);
		msg.Format("%6d    %10.4f    %10.5e  %10.5e",i+1,ipt->drwdown,ipt->vx,ipt->vy);
		td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	}
	td.SelectObject(hfp);
	hf.DeleteObject();
	return iyp;
}

float CBemSolveDoc::Flow (CElement* el)
{                                           
	float dx,dy,dl,bet,q1,q2,dfi,x1,x2,y1,y2;

   	CNode* b1=GetNode(el->nod1);CNode* b2=GetNode(el->nod2);
   	b1->Coord(x1,y1);b2->Coord(x2,y2);
   	dx=x2-x1;dy=y2-y1;
   	dl=sqrt(dx*dx+dy*dy);
   	bet=atan2 (dx,dy);
   	q1=el->der*cos(bet)*tx;q2=el->der*sin(bet)*ty*txy;
   	dfi=sqrt (q1*q1+q2*q2)*dl;if (el->der<0) dfi=-dfi;
   	return dfi;
}

int CBemSolveDoc::PrintWell(CDC &td, int iy)
{
	CFont hf,*hfp;
	CString msg;
	hf.CreateFontIndirect(&lfntw);
	int i,iyp;
	iyp=iy;
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	msg="Wells";
	td.TextOut(bounl,iyp,msg);iyp-=2*sz.cy;
	msg="Well        Coordinates          Yield    Diameter";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	msg="---------------------------------------------------";
	td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	for (i=0;i<Wells.GetSize();i++)
	{
		CWell* wl=GetWell(i);
		msg.Format("   %10.4f %10.4f %11.5f  %10.4f",wl->xz,wl->yz,wl->yield,wl->diam);
		msg=wl->name+msg;
		td.TextOut(bounl,iyp,msg);iyp-=sz.cy;
	}
	td.SelectObject(hfp);
	hf.DeleteObject();
	return iyp;
}
