// UnsDisDoc.cpp : implementation of the CUnsDisDoc class
//

#include "stdafx.h"
#include "math.h"
#include "UnsDis.h"

#include "UnsDisDoc.h"
#include "layeradd.h"
#include "boundary.h"
#include "timeinter.h"
#include "formataxes.h"

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

/////////////////////////////////////////////////////////////////////////////
// CUnsDisDoc

IMPLEMENT_DYNCREATE(CUnsDisDoc, CDocument)

BEGIN_MESSAGE_MAP(CUnsDisDoc, CDocument)
	//{{AFX_MSG_MAP(CUnsDisDoc)
	ON_COMMAND(ID_TIME, OnTime)
	ON_COMMAND(ID_SAVE_TXT, OnSaveTxt)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUnsDisDoc construction/destruction

CUnsDisDoc::CUnsDisDoc()
{
}

CUnsDisDoc::~CUnsDisDoc()
{
}

BOOL CUnsDisDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	meas=1000;topmarg=botmarg=15;lemarg=rimarg=15;
	memset (&ftyp,0,sizeof(LOGFONT));
	ftyp.lfHeight=-25;
	strcpy (ftyp.lfFaceName,"Courier New");

	bcfup=0;bcflo=1;vfup=vflo=0.0f;
	bccup=0;bcclo=1;vcup=100.0f;vclo=0.0f;

	deltin=0.01f;errt=1e-4;eps=1.0f;dtmax=2.0f;
	cmin=0.0f;
	pmin=1000.0f;

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CUnsDisDoc serialization

void CUnsDisDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		ar << name << meas << topmarg << botmarg << lemarg << rimarg;
		ar << bcfup << bcflo << bccup << bcclo << vfup << vflo << vcup << vclo;
		ar << pmin << cmin << pmax << cmax << pstp << pstl << cstp << cstl;
		ar << deltin << dtmax << eps << errt << maxit;
		ar.Write(&ftyp,sizeof(LOGFONT));
	}
	else
	{
		ar >> name >> meas >> topmarg >> botmarg >> lemarg >> rimarg;
		ar >> bcfup >> bcflo >> bccup >> bcclo >> vfup >> vflo >> vcup >> vclo;
		ar >> pmin >> cmin >> pmax >> cmax >> pstp >> pstl >> cstp >> cstl;
		ar >> deltin >> dtmax >> eps >> errt >> maxit;
		ar.Read(&ftyp,sizeof(LOGFONT));
	}
	Tim.Serialize(ar);
	Layers.Serialize(ar);
	Elements.Serialize(ar);
	TimeInt.Serialize(ar);
}

/////////////////////////////////////////////////////////////////////////////
// CUnsDisDoc diagnostics

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

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

/////////////////////////////////////////////////////////////////////////////
// CUnsDisDoc commands

void CUnsDisDoc::DeleteContents() 
{
	int i=0;
	while (i<Elements.GetSize())
	{
		delete Elements.GetAt(i++);
	}	                     
	Elements.RemoveAll();
	i=0;
	while (i<Layers.GetSize())
	{
		delete Layers.GetAt(i++);
	}	                     
	Layers.RemoveAll();
	i=0;
	while (i<TimeInt.GetSize())
	{
		delete TimeInt.GetAt(i++);
	}	                     
	TimeInt.RemoveAll();
	Tim.RemoveAll();	
	CDocument::DeleteContents();
}

CTimeStep* CUnsDisDoc::GetTime(int i)
{
	return (CTimeStep*)TimeInt.GetAt(i);
}

CLayer* CUnsDisDoc::GetLayer(int i)
{
	return (CLayer*)Layers.GetAt(i);
}

CElement* CUnsDisDoc::GetElement(int i)
{
	return (CElement*)Elements.GetAt(i);
}

CTimeStep* CUnsDisDoc::AddTime(float t)
{
	CTimeStep* tm=new CTimeStep(t);
	TimeInt.Add(tm);
	SetModifiedFlag();
	return tm;
}

void CUnsDisDoc::AddLayer()
{
	CLayerAdd lad;
	float zs=0.0f;
	lad.textok="Next";lad.textcan="Stop";
	for (;;)
	{
		lad.m_z1=zs;
		if (lad.DoModal()==IDCANCEL) break;
		CLayer* lr=new CLayer(lad.m_z1,lad.m_z2,lad.m_nel,lad.m_ths,lad.m_thr,lad.m_wn,lad.m_alpha,lad.m_ksat);
		lr->disp=lad.m_disp;lr->ro=lad.m_ro;
		lr->potin=lad.m_initp;lr->kd=lad.m_kd;
		lr->stn=lad.m_nf;
		Layers.Add(lr);
		zs=lad.m_z2;
		SetModifiedFlag();
	}
}

void CUnsDisDoc::EditLayer(int nlay)
{
	CLayerAdd lad;
	CLayer* lr=GetLayer(nlay);
	lad.m_z1=lr->zbeg;lad.m_z2=lr->zend;lad.m_alpha=lr->alpha;
	lad.m_disp=lr->disp;lad.m_ksat=lr->ksat;lad.m_nel=lr->nel;
	lad.m_ro=lr->ro;lad.m_thr=lr->thr;
	lad.m_ths=lr->ths;lad.m_wn=lr->wn;
	lad.m_initp=lr->potin;lad.m_kd=lr->kd;lad.m_nf=lr->stn;
	lad.m_initc=lr->conin;
	if (lad.DoModal()==IDOK)
	{
		lr->alpha=lad.m_alpha;lr->ksat=lad.m_ksat;
		lr->nel=lad.m_nel;lr->thr=lad.m_thr;lr->ths=lad.m_ths;
		lr->wn=lad.m_wn;lr->zbeg=lad.m_z1;lr->zend=lad.m_z2;
		lr->disp=lad.m_disp;lr->ro=lad.m_ro;
		lr->potin=lad.m_initp;lr->kd=lad.m_kd;
		lr->stn=lad.m_nf;lr->conin=lad.m_initc;
		SetModifiedFlag();
	}
}

void CUnsDisDoc::Generate()
{
	int i,nod;
	float dz,z1,z2;
	nod=0;
	i=0;
	while (i<Elements.GetSize())
	{
		delete Elements.GetAt(i++);
	}	                     
	Elements.RemoveAll();
	for (i=0;i<Layers.GetSize();i++)
	{
		CLayer* lr=GetLayer(i);
		dz=(lr->zend-lr->zbeg)/(float)lr->nel;
		z2=lr->zend-dz*0.5;
		for (z1=lr->zbeg;z1<z2;z1+=dz)
		{
			CElement* el=new CElement(z1,z1+dz);
			el->nlay=i;
			Elements.Add(el);
		}
	}
}

void CUnsDisDoc::Solve(CDC& td,RECT rct)
{
/******************************************
 *        Start of simulation             *
 ******************************************/
	float *a,*b,*c,*d,*pa,*pb,*pc,*r1,*r2;
	float *psi,*prvpsi,*cpsi,*pp,*prpsi;
	float *cp, *cpp,*cq;
	int itl,i,k,itt,nel,nds,iter,nelem1,k1,k2,ntim,kon;
	int ix,iy;
	float time,dt1,dtt,ks1,ks2,c1,c2,thet1,thet2,dl,dl2,tmax;
	float a11,a12,a21,a22,b11,b12,b21,b22,v1,v2,dis1,dis2,ret,q1,q2,dth1,dth2;
	float r11,r12,r22,epsn,aa,bb,ccp,errg,dqz,cr1,cr2,dp1,dp2,al,cpr,pom,ap,qp1,qp2;
	float q,delt,delt1,delt2,daxp,daxc,pscl,cscl;
	RECT rctp,rctc;
	CPen pbl(PS_SOLID,2,RGB(0,0,255)),*ppr;

	rctp=rctc=rct;rctp.right=(rct.left+rct.right)/2;
	rctc.left=rctp.right;
	rctp.top+=100;rctc.top+=100;rctc.left+=200;rctp.left+=200;
	daxp=rctp.right-rctp.left;daxc=rctc.right-rctc.left;
	ppr=td.SelectObject(&pbl);

	itl=0;
	time=0.0f;
	dt1=deltin;
	nel=Elements.GetSize();
	nds=nel+1;nelem1=nel-1;
	ntim=Tim.GetSize();
	a=new float[nds];b=new float[nds];c=new float[nds];
	pa=new float[nds];pb=new float[nds];pc=new float[nds];
	r1=new float[nds];r2=new float[nds];d=new float[nds];
	psi=new float[nds];prvpsi=new float[nds];prpsi=new float[nds];
	pp=new float[nds];cpsi=new float[nds];
	cp=new float[nds];cpp=new float[nds];cq=new float[nds];
	i=0;
	while (i<TimeInt.GetSize())
	{
		delete TimeInt.GetAt(i++);
	}	                     
	TimeInt.RemoveAll();
	CTimeStep* tstp=AddTime(0.0f);

	for (i=0;i<nds;i++)
	{
		k=i;if (k==nel) k=nel-1;
		CElement* el=GetElement(k);
		CLayer* lr=GetLayer(el->nlay);
		CResult* rs=new CResult(lr->potin);
		rs->conc=lr->conin;
		if (rs->conc==0.0f) rs->cons=0.0f;
		else rs->cons=rs->conc*lr->kd*pow(rs->conc,lr->stn);
		rs->theta=lr->Theta(rs->psi);
		tstp->Results.Add(rs);
		prvpsi[i]=prpsi[i]=pp[i]=psi[i]=rs->psi;
		cp[i]=cpp[i]=rs->conc;cq[i]=rs->cons;
	}

//******** time steps ********
	delt=deltin;cmin=pmin=1e30;pmax=cmax=-1e30;
	for (itt=0;itt<ntim;itt++)
	{
		tmax=Tim[itt];

//------ temporary time steps ------------

		do
		{
			itl++;
			time+=delt;
			if (time>tmax) time=tmax;

//------------ estimation of psi in time t+1/2delt -----------

			if (itl>1) dtt=0.5*delt/dt1;
			for (i=0;i<nds;i++)
			{
				if (itl>1) cpsi[i]=prvpsi[i]+dtt*(prvpsi[i]-prpsi[i]);
				else cpsi[i]=prvpsi[i];
			}
			iter=0;

//******** loop of iterations **********

			kon=0;
			do
			{
				iter++;
				for (i=0;i<nds;i++) a[i]=b[i]=c[i]=pa[i]=pb[i]=pc[i]=0.0f;

//----------- matrix of element -------------
				for (k=0;k<nel;k++)
				{
					CElement* el=GetElement(k);
					dl=el->z2-el->z1;
					k1=k+1;
					CLayer* lr=GetLayer(el->nlay);
					ks1=lr->Kuns(cpsi[k]);ks2=lr->Kuns(cpsi[k1]);
					thet1=lr->Theta(cpsi[k]);thet2=lr->Theta(cpsi[k1]);
					c1=lr->Capac(cpsi[k]);c2=lr->Capac(cpsi[k1]);
					a22=a11=(ks1+ks2)*0.5f/dl;a21=a12=-a11;
					b11=dl*(c1/3.+c2/6.)/delt;
					b22=dl*(c2/3.+c1/6.)/delt;
					b12=b21=0.0f;
					b[k]+=eps*a11+b11;c[k]+=eps*a12+b12;
					a[k1]+=eps*a21+b21;b[k1]+=eps*a22+b22;
					pb[k]+=(eps-1.0f)*a11+b11;pc[k]+=(eps-1.0f)*a12+b12;
					pa[k1]+=(eps-1.0f)*a21+b21;pb[k1]+=(eps-1.0f)*a22+b22;
					r1[k]=-0.5f*(ks1+ks2);r2[k]=0.5f*(ks1+ks2);
				}

//------------- boundary conditions ------------
				if (bcfup)
				{
					a[0]=0;d[0]=pb[0]*prvpsi[0]+pc[0]*prvpsi[1]+r1[0]+vfup;
				}
				else
				{
					a[0]=c[0]=0.0f;b[0]=1.0f;d[0]=vfup;
				}
				for (k=0;k<nelem1;k++)
				{		
					k1=k+1;
					aa=pa[k1];bb=pb[k1];ccp=pc[k1];
					d[k1]=aa*prvpsi[k]+bb*prvpsi[k1]+ccp*prvpsi[k+2]+r2[k]+r1[k1];
				}
				if (bcflo)
				{
					c[nel]=0.0f;
					d[nel]=pa[nel]*prvpsi[nelem1]+pb[nel]*prvpsi[nel]+r2[nelem1]-vflo;
				}
				else
				{
					a[nel]=c[nel]=0.0f;
					b[nel]=1.0f;d[nel]=vflo;
				}
				SolvEq (nds,a,b,c,d,psi);
//------------- test of convergention -------------------------
				epsn=1e-20;
				for (i=1;i<nel;i++)
				{
					errg=(psi[i]-pp[i])/psi[i];
					errg=fabs(errg);
					if (errg>epsn) epsn=errg;
				}
				if (epsn>errt||iter==1)
				{
					for (i=0;i<nds;i++)
					{
						cpsi[i]=(prvpsi[i]+psi[i])*0.5f;
						pp[i]=psi[i];
					}
				}
				if (epsn<=errt||iter==maxit) kon=1;
				if (iter==1) kon=0;
			}
			while (kon==0);
// ------------- end of iterations ----------
// ------------- solution of dispersion ---------  
			for (i=0;i<nds;i++) a[i]=b[i]=c[i]=pa[i]=pb[i]=pc[i]=0.0f;
			for (k=0;k<nel;k++)
			{
				k1=k+1;k2=k+2;
				CElement* el1=GetElement(k);
				CLayer* lr=GetLayer(el1->nlay);
				dl=el1->leng();
				thet1=lr->Theta(psi[k]);thet2=lr->Theta(psi[k1]);
				dth1=(thet1-lr->Theta(prvpsi[k]))/delt;
				dth2=(thet2-lr->Theta(prvpsi[k1]))/delt;
				if (k==0)
				{
					CElement* el2=GetElement(k1);
					dl2=el2->leng();
					if (bcfup==1) q1=vfup;
					else q1=((psi[0]-psi[1]+dl)*eps*r2[0]+(prvpsi[0]-prvpsi[1]+dl)*(1.0f-eps)*r2[0])/dl;
					q2=((psi[1]-psi[2]+dl2)*eps*r2[1]+(prvpsi[1]-prvpsi[2]+dl2)*(1.0f-eps)*r2[1])/dl2;
				}
				else
				{
					if (k==nelem1)
					{
						if (bcflo) q2=vflo;
						else q2=(psi[k]-psi[k1]+dl)*eps*r2[k]/dl+(prvpsi[k]-prvpsi[k1]+dl)*(1.0f-eps)*r2[k]/dl;
						q1=((psi[k]-psi[k1]+dl)*eps*r2[k]+(prvpsi[k]-prvpsi[k1]+dl)*(1.0f-eps)*r2[k])/dl;
					}
					else
					{
						CElement* el2=GetElement(k1);
						dl2=el2->leng();
						q1=((psi[k]-psi[k1]+dl)*eps*r2[k]+(prvpsi[k]-prvpsi[k1]+dl)*(1.0f-eps)*r2[k])/dl;
						q2=((psi[k1]-psi[k2]+dl2)*eps*r2[k1]+(prvpsi[k1]-prvpsi[k2]+dl2)*(1.0f-eps)*r2[k1])/dl2;
					}
				}
				v1=fabs(q1)/thet1;v2=fabs(q2)/thet2;
				dqz=(q2-q1)/dl;
				cr1=dth1+dqz;
				cr2=dth2+dqz;
				r11=dl*(3.0f*cr1+cr2)/12.0f;
				r22=dl*(3.0f*cr2+cr1)/12.0f;
				r12=dl*(cr2+cr1)/12.0f;
				dp1=Diff (thet1);dp2=Diff (thet2);
				al=lr->disp;dis1=al*v1+dp1;
				cpr=(cp[k]+cp[k1])*0.5f;
				if (cpr<1e-6) ret=1;
				else
				{
					pom=pow(cpr,lr->stn-1.0f);
					ret=1.0f+lr->ro*lr->kd*lr->stn*pom/thet1;
				}
				dis2=al*v2+dp2;
				ap=(dis1+dis2)*0.5/dl;
				qp1=(2.0f*q1+q2)/6.0f;qp2=(2.0f*q2+q1)/6.0f;
				a11=ap-qp1+r11;a12=-ap+qp1+r12;
				a21=-ap-qp2+r12;a22=ap+qp2+r22;
				b11=ret*dl*(thet1/3.0f+thet2/6.0f)/delt;
				b22=ret*dl*(thet2/3.0f+thet1/6.0f)/delt;
				b12=b21=0.0f;
				b[k]+=eps*a11+b11;c[k]+=eps*a12+b12;
				a[k1]+=eps*a21+b21;b[k1]+=eps*a22+b22;
				pb[k]+=(eps-1.0f)*a11+b11;pc[k]+=(eps-1.0f)*a12+b12;
				pa[k1]+=(eps-1.0f)*a21+b21;pb[k1]+=(eps-1.0f)*a22+b22;
			}

//--------- boundary conditions --------------

			if (bccup!=0) 
			{
				a[0]=0.0f;d[0]=pb[0]*cpp[0]+pc[0]*cpp[1]+vcup;
			}
			else 
			{
				a[0]=c[0]=0.0f;b[0]=1.0f;d[0]=vcup;
			}
			for (k=0;k<nelem1;k++)
			{
				k1=k+1;
				aa=pa[k1];bb=pb[k1];ccp=pc[k1];
				d[k1]=aa*cpp[k]+bb*cpp[k1]+ccp*cpp[k+2];
			}
			if (bcclo!=0)
			{
				c[nel]=0.0f;
				d[nel]=pa[nel]*cpp[nelem1]+pb[nel]*cpp[nel]+vclo;
			}
			else
			{
				a[nel]=c[nel]=0.0f;b[nel]=1.0f;d[nel]=vclo;
			}
			SolvEq (nds,a,b,c,d,cp);
			for (k=0;k<nds;k++)
			{
				k1=k;
				if (k==nel) k1=nel-1;
				CElement* el=GetElement(k1);
				CLayer* lr=GetLayer(el->nlay);
				if (cp[k]<1e-6) cq[k]=0;
				else
				{
					pom=pow(cp[k],lr->stn);
					cq[k]=lr->kd*pom;
				}
			}
//------------ uchovanie hodnot psi pre dalsi cas.krok ----------
			for (i=0;i<nds;i++)
			{
				prpsi[i]=prvpsi[i];prvpsi[i]=psi[i];
				if (cp[i]>=0.0f) cpp[i]=cp[i];
				else cpp[i]=0.0f;
			}
//----------- vypocet noveho delt -------------
			dt1=delt;
			if (bcfup==0)
			{
				CElement* el=GetElement(0);
				dl=el->leng();
				q=(psi[0]-psi[1]+dl)*eps*r2[0]/dl+(prvpsi[0]-prvpsi[1]+dl)*(1.0f-eps)*r2[0]/dl;
			}
			else q=vcup;
			if (fabs(q)<1e-10) q=1e-10;
			delt1=2.0f*delt;
			delt2=0.1f*dl/fabs(q);
			if (delt1<delt2) delt=delt1;else delt=delt2;
			if (iter>5) delt=delt*0.5;
			if (delt>dtmax) delt=dtmax;
		}
		while (time<tmax);   
//---- end of time cyklus -----
		CTimeStep* ts=new CTimeStep(tmax);
		ts->pmax=ts->cmax=0.0f;
		ts->pmin=ts->cmin=1e30;
		for (i=0;i<nds;i++)
		{
			CResult* rs=new CResult(psi[i]);
			k1=i;
			if (i==nel) k1=nel-1;
			CElement* el=GetElement(k1);
			CLayer* lr=GetLayer(el->nlay);
			rs->conc=cp[i];rs->cons=cq[i];rs->theta=lr->Theta(psi[i]);
			ts->Results.Add(rs);
			if (rs->conc>ts->cmax) ts->cmax=rs->conc;
			if (rs->psi>ts->pmax) ts->pmax=rs->psi;
			if (rs->conc<ts->cmin) ts->cmin=rs->conc;
			if (rs->psi<ts->pmin) ts->pmin=rs->psi;
		}
		TimeInt.Add(ts);
		if (itt==0)
		{
			if (ts->pmax>pmax) pmax=ts->pmax;
			if (ts->cmax>cmax) cmax=ts->cmax;
			if (ts->pmin<pmin) pmin=ts->pmin;
			if (ts->cmin<cmin) cmin=ts->cmin;
			if (cmin<0.0f) cmin=0.0f;
			pscl=fabs(pmax-pmin);
			if (pscl<1.0f) pstp=0.1f;
			else
			{
				if (pscl<10.0f) pstp=1.0f;
				else
				{
					if (pscl<100.0f) pstp=10.0f; 
					else pstp=ceil(pscl/100.0f)*10.0f;
				}
			}
			cscl=fabs(cmax-cmin);
			if (cscl<1.0f) cstp=0.1f;
			else
			{
				if (cscl<10.0f) cstp=1.0f;
				else
				{
					if (cscl<190.0f) cstp=10.0f;
					else cstp=50.0f;
				}
			}
			pstl=2.0f*pstp;cstl=2.0*cstp;
		}
		for (i=0;i<nds;i++)
		{
			CResult* rs=ts->GetResult(i);
			k=i;if (k==nel) k=nel-1;
			CElement* el=GetElement(k);
			ix=rctp.top+(int)(el->z1*1e4/meas);
			if (i==nel) ix=rctp.top+(int)(el->z2*1e4/meas);
			iy=rctp.left+(int)((rs->psi-pmin)*daxp/(pmax-pmin));
			if (i==0) td.MoveTo(iy,ix);
			else td.LineTo(iy,ix);
		}
		for (i=0;i<nds;i++)
		{
			CResult* rs=ts->GetResult(i);
			k=i;if (k==nel) k=nel-1;
			CElement* el=GetElement(k);
			ix=rctc.top+(int)(el->z1*1e4/meas);
			if (i==nel) ix=rctc.top+(int)(el->z2*1e4/meas);
			iy=rctc.left+(int)((rs->conc-cmin)*daxc/(cmax-cmin));
			if (i==0) td.MoveTo(iy,ix);
			else td.LineTo(iy,ix);
		}
	}

	delete a;delete b;delete c;delete d;
	delete pa;delete pb;delete pc;delete pp;
	delete r1;delete r2;delete psi;delete prvpsi;delete prpsi;
	delete cpsi;delete cp;delete cpp;delete cq;
}

CSize CUnsDisDoc::GetDocSize()
{
	CUnsDisApp* pApp=(CUnsDisApp*)AfxGetApp();
	CSize sz;
	sz.cx=pApp->width*10;sz.cy=pApp->height*10;
	return sz;
}

void CUnsDisDoc::PlotLay(CDC &td,RECT r)
{
	int i,iy;
	CFont *hfp,hfh,hfv;
	LOGFONT ftv;
	RECT rlay;
	CString msg;
	int nl=Layers.GetSize();
	if (nl==0) return;
	ftv=ftyp;ftv.lfEscapement=900;
	hfh.CreateFontIndirect(&ftyp);
	hfv.CreateFontIndirect(&ftv);
	hfp=td.SelectObject(&hfv);
	rlay.left=r.left;rlay.right=r.left+100;
	iy=r.top+100;
	UINT tap=td.SetTextAlign(TA_TOP | TA_LEFT);
	msg="Layers";td.TextOut(rlay.left+50,r.top+90,msg);
	td.SetTextAlign(tap);
	td.SelectObject(&hfh);
	for (i=0;i<nl;i++)
	{
		CLayer* lr=GetLayer(i);
		rlay.top=iy;
		rlay.bottom=r.top+(int)(lr->zend*1e4/meas)+100;
		td.Rectangle(&rlay);
		msg.Format ("%d",i+1);
		td.DrawText(msg,&rlay,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		iy=rlay.bottom-1;
	}
	td.SelectObject(hfp);
	hfh.DeleteObject();
	hfv.DeleteObject();
}

void CUnsDisDoc::PlotElems(CDC &td, RECT r)
{
	int i,iy;
	CFont *hfp,hfh,hfv;
	LOGFONT ftv;
	RECT relem;
	CString msg;
	int nel=Elements.GetSize();
	if (nel==0) return;
	ftv=ftyp;ftv.lfEscapement=900;
	hfh.CreateFontIndirect(&ftyp);
	hfv.CreateFontIndirect(&ftv);
	hfp=td.SelectObject(&hfv);
	relem.left=r.left+100;relem.right=r.left+200;
	iy=r.top+100;
	UINT tap=td.SetTextAlign(TA_TOP | TA_LEFT);
	msg="Elements";td.TextOut(relem.left+50,r.top+90,msg);
	td.SetTextAlign(tap);
	td.SelectObject(&hfh);
	for (i=0;i<nel;i++)
	{
		CElement* el=GetElement(i);
		relem.top=iy;
		relem.bottom=r.top+(int)(el->z2*1e4/meas)+100;
		td.Rectangle(&relem);
		msg.Format ("%d",i+1);
		td.DrawText(msg,&relem,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
		iy=relem.bottom-1;
	}
	td.SelectObject(hfp);
	hfh.DeleteObject();
	hfv.DeleteObject();
}

void CUnsDisDoc::OpenInitCon()
{
	char szFile[256];
	UINT  cbString;
	char  chReplace;    /* string separator for szFilter */
	char  szFilter[256];
	CString menf,msg,msp;
	int i,j,nod;
	float psi,cnc,cns;
	CFileDialog fd(TRUE);    
	CStdioFile hf;

	nod=Elements.GetSize()+1;
	if (nod<2) return;
    strcpy(szFilter,"Text files (*.PRN)|*.prn|all (*.*)|*.*|");
    cbString=strlen(szFilter);
	chReplace = szFilter[cbString - 1]; /* retrieve wildcard */
    szFile[0]=0;
    
    for (i = 0; szFilter[i] != '\0'; i++) 
	{
    	if (szFilter[i] == chReplace) szFilter[i] = '\0';
	}

/* Set all structure members to zero. */

	fd.m_ofn.lpstrFilter = szFilter;
	fd.m_ofn.nFilterIndex = 1;
	fd.m_ofn.lpstrFile= szFile;
	fd.m_ofn.nMaxFile = sizeof(szFile);
	fd.m_ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ENABLEHOOK | OFN_EXPLORER;


	if (fd.DoModal()==IDOK) 
	{
		menf=fd.GetPathName();
		try
		{
			hf.Open(menf,CFile::typeText | CFile::modeRead);
			CTimeStep* tm=new CTimeStep (0.0f);
			i=0;
			while (i<TimeInt.GetSize())
			{
				delete TimeInt.GetAt(i++);
			}	                     
			TimeInt.RemoveAll();
			pmax=cmax=0.0f;
			pmin=cmin=1000.0f;
			for (i=0;;i++)
			{
				if (i>=nod) break;
				if (!hf.ReadString(msg)) break;
				msg.TrimLeft();msg.TrimRight();
				j=msg.Find(' ');
				if (j<0)
				{
					psi=atof(msg);cnc=cns=0.0f;
				}
				else
				{
					msp=msg.Left(j);psi=atof(msp);
					msp=msg.Mid(j);msp.TrimLeft();msp.TrimRight();
					j=msp.Find(' ');
					if (j<0)
					{
						cnc=atof(msp);cns=0.0f;
					}
					else
					{
						msg=msp.Left(j);cnc=atof(msg);
						msg=msp.Mid(j);cns=atof(msg);
					}
				}
				if (fabs(psi)>pmax) pmax=fabs(psi);
				if (cnc>cmax) cmax=cnc;
				if (fabs(psi)<pmin) pmin=fabs(psi);
				if (cnc<cmin) cmin=cnc;
				CResult* rs=new CResult(psi);
				rs->conc=cnc;rs->cons=cns;
				tm->Results.Add(rs);
			}
			TimeInt.Add(tm);
			if (pmax<1.0f) pstp=0.1f;
			else
				if (pmax<10.0f) pstp=1.0f;
				else
					if (pmax<100.0f) pstp=10.0f; 
					else pstp=ceil(pmax/100.0f)*10.0f;
			if (cmax<1.0f) cstp=0.1f;
			else
			{
				if (cmax<10.0f) cstp=1.0f;
				else
				{
					if (cmax<100.0f) cstp=10.0f;
					else cstp=50.0f;
				}
			}
			pstl=2.0f*pstp;cstl=2.0*cstp;
			hf.Close();
		}
		catch (CFileException* e)
		{
			msg.Format("Error %d in file ",e->m_cause);
			msg+=menf;
			AfxMessageBox(msg);
			throw;
		}
	}

}

void CUnsDisDoc::EditBC()
{
	CBoundary bn ("Boundary conditions");
	bn.flowpg.m_kindup=bcfup;bn.flowpg.m_kindlow=bcflo;
	bn.flowpg.m_valup=vfup;bn.flowpg.m_valow=vflo;
	bn.concpg.m_kindup=bccup;bn.concpg.m_kindlow=bcclo;
	bn.concpg.m_valup=vcup;bn.concpg.m_valow=vclo;
	if (bn.DoModal()==IDOK)
	{
		bcfup=bn.flowpg.m_kindup;bcflo=bn.flowpg.m_kindlow;
		vfup=bn.flowpg.m_valup;vflo=bn.flowpg.m_valow;
		bccup=bn.concpg.m_kindup;bcclo=bn.concpg.m_kindlow;
		vcup=bn.concpg.m_valup;vclo=bn.concpg.m_valow;
	}
}

float CUnsDisDoc::Diff(float th)
{
	return (1.333e-5*exp(10.0*th));   // molecular diffusion as a fu. of moisture
}

void CUnsDisDoc::SolvEq(int n, float *a, float *b, float *c, float *d, float *rs)
{
	int i,i1,n1;
	float *bb,*gg;
	bb=new float[n];gg=new float[n];
	bb[0]=b[0];
	gg[0]=d[0]/b[0];
	for (i=1;i<n;i++)
	{
		i1=i-1;
		bb[i]=b[i]-a[i]*c[i1]/bb[i1];
		gg[i]=(d[i]-a[i]*gg[i1])/bb[i];
	}
	rs[n]=gg[n];n1=n-1;
	for (i=n1;i>=0;i--)
	{
		rs[i]=gg[i]-c[i]*rs[i+1]/bb[i];
	}
	delete bb;delete gg;

}

void CUnsDisDoc::OnTime() 
{
	CTimeInter tim;
	tim.pDoc=this;
	tim.m_delt=deltin;tim.m_dtmax=dtmax;tim.m_maxit=maxit;
	tim.m_schem=eps;tim.m_tol=errt;
	if (tim.DoModal()==IDOK)
	{
		deltin=tim.m_delt;dtmax=tim.m_dtmax;
		eps=tim.m_schem;errt=tim.m_tol;maxit=tim.m_maxit;
	}
}

void CUnsDisDoc::yax(CDC &td, float ymin, float ymax, float ytic, RECT r, int tlen)
{
	int iy;
	float y,dy,yp,dyf;
	td.MoveTo(r.left,r.top);td.LineTo(r.right,r.top);
	dy=r.right-r.left;dyf=ymax-ymin;
	for (y=ymin;y<ymax+ytic*0.5f;y+=ytic)
	{
		yp=dy*(y-ymin)/dyf;
		if (y>ymax) break;
		iy=(int)yp+r.left;
		td.MoveTo(iy,r.top);td.LineTo(iy,r.top-tlen);td.LineTo(iy,r.top+tlen);
	}
}

void CUnsDisDoc::ylabel (CDC &td, float ymin, float ymax, float ytic, RECT r, int tlen, int dp)
{
	int iy;
	float y,yp,dyf,dy;
	CString msg;
	CFont hf,*hfp;
	hf.CreateFontIndirect(&ftyp);
	hfp=td.SelectObject(&hf);
	dy=r.right-r.left;dyf=ymax-ymin;
	UINT tap=td.SetTextAlign(TA_BOTTOM | TA_CENTER);
	for (y=ymin;y<ymax+ytic*0.5f;y+=ytic)
	{
		yp=dy*(y-ymin)/dyf;
		if (y>ymax) break;
		iy=(int)yp+r.left;
		msg.Format("%.*f",dp,y);
		td.TextOut(iy,r.top-tlen,msg);
	}
	td.SetTextAlign(tap);
}

void CUnsDisDoc::PlotAxes(CDC &td, RECT rct)
{
	RECT rctp,rctc;
	rctp.left=rct.left+200;rctp.top=rct.top+100;rctp.right=(rct.left+rct.right)/2;
	rctc.left=rctp.right;rctp.bottom=rctc.bottom=rct.bottom;
	rctc.right=rct.right;rctc.top=rct.top;
	yax (td,pmin,pmax,pstp,rctp,5);
	ylabel (td,pmin,pmax,pstl,rctp,5,2);
	PlotElems (td,rctc);rctc.left+=200;rctc.top+=100;
	if (cmax>0.0f)
	{
		yax (td,cmin,cmax,cstp,rctc,5);
		ylabel (td,cmin,cmax,cstl,rctc,5,1);
	}
}

void CUnsDisDoc::FormAxes()
{
	CFormatAxes fx;
	fx.m_clab=cstl;fx.m_cmax=cmax;fx.m_cmin=cmin;fx.m_ctic=cstp;
	fx.m_plab=pstl;fx.m_pmax=pmax;fx.m_pmin=pmin;fx.m_ptic=pstp;
	if (fx.DoModal()==IDOK)
	{
		cstl=fx.m_clab;cmax=fx.m_cmax;cmin=fx.m_cmin;cstp=fx.m_ctic;
		pstl=fx.m_plab;pmax=fx.m_pmax;pmin=fx.m_pmin;pstp=fx.m_ptic;
	}
}

void CUnsDisDoc::PlotTime(CDC &td, RECT rct, int istart, int iend)
{
	int i,j,k,nel,ix,iy;
	float daxp,daxc;
	RECT rctp,rctc;
	rctp.left=rct.left+200;rctp.top=rct.top+100;rctp.right=(rct.left+rct.right)/2;
	rctc.left=rctp.right+200;rctp.bottom=rctc.bottom=rct.bottom;
	rctc.right=rct.right;rctc.top=rctp.top;
	daxp=rctp.right-rctp.left;daxc=rctc.right-rctc.left;
	nel=Elements.GetSize();
	for (j=istart;j<iend;j++)
	{
		CTimeStep* ts=GetTime(j);
		for (i=0;i<ts->Results.GetSize();i++)
		{
			CResult* rs=ts->GetResult(i);
			k=i;if (k==nel) k=nel-1;
			CElement* el=GetElement(k);
			ix=rctp.top+(int)(el->z1*1e4/meas);
			if (i==nel) ix=rctp.top+(int)(el->z2*1e4/meas);
			iy=rctp.left+(int)((rs->psi-pmin)*daxp/(pmax-pmin));
			if (i==0) td.MoveTo(iy,ix);
			else td.LineTo(iy,ix);
		}
		for (i=0;i<ts->Results.GetSize();i++)
		{
			CResult* rs=ts->GetResult(i);
			k=i;if (k==nel) k=nel-1;
			CElement* el=GetElement(k);
			ix=rctc.top+(int)(el->z1*1e4/meas);
			if (i==nel) ix=rctc.top+(int)(el->z2*1e4/meas);
			iy=rctc.left+(int)((rs->conc-cmin)*daxc/(cmax-cmin));
			if (i==0) td.MoveTo(iy,ix);
			else td.LineTo(iy,ix);
		}
	}
}

void CUnsDisDoc::DelLayer(int nl)
{
	CLayer* lr=GetLayer(nl);
	delete lr;
	Layers.RemoveAt(nl);
}

void CUnsDisDoc::Font()
{
	LOGFONT pom;
	memcpy (&pom,&ftyp,sizeof(LOGFONT));
	CFontDialog dlg(&pom, CF_SCREENFONTS|CF_INITTOLOGFONTSTRUCT);
	if (dlg.DoModal() == IDOK)
	{      
		memcpy (&ftyp,&pom,sizeof(LOGFONT));
		SetModifiedFlag();
	}
}

void CUnsDisDoc::PrintRes(CDC &td, RECT r, int istart, int iend)
{
	int i,j,nel,ix,iy,ixx,k;
	float z;
	CFont hf,*hfp;
	CString msg;
	ix=r.left+5;iy=r.top+20;ixx=ix+40;
	hf.CreateFontIndirect(&ftyp);
	hfp=td.SelectObject(&hf);
	CSize sz=td.GetTextExtent("M",1);
	nel=Elements.GetSize();
	for (j=istart;j<iend;j++)
	{
		CTimeStep* ts=GetTime(j);
		msg.Format("Time: %f",ts->time);
		td.TextOut(ix,iy,msg);iy+=sz.cy;
		for (i=0;i<ts->Results.GetSize();i++)
		{
			CResult* rs=ts->GetResult(i);
			k=i;if (k==nel) k=nel-1;
			CElement* el=GetElement(k);
			z=el->z1;if (i==nel) z=el->z2;
			msg.Format ("%2d. %8.2f %10.3f %10.3f %10.3f",i+1,z,rs->psi,rs->conc,rs->cons);
			td.TextOut (ixx,iy,msg);iy+=sz.cy;
		}
	}
	td.SelectObject(hfp);
	hf.DeleteObject();
}

void CUnsDisDoc::OnSaveTxt() 
{
	char szFile[256];
	UINT  cbString;
	int i,j,nel,k;
	float z;
	char  chReplace;    /* string separator for szFilter */
	char  szFilter[256];
	CString namef,msg;
	CFileDialog fd(FALSE);    
	CStdioFile hf;

    strcpy(szFilter,"Text file (*.TXT)|*.txt|All files (*.*)|*.*|");
    cbString=strlen(szFilter);
	chReplace = szFilter[cbString - 1]; /* retrieve wildcard */
    szFile[0]=0;
    
    for (i = 0; szFilter[i] != '\0'; i++) 
	{
    	if (szFilter[i] == chReplace) szFilter[i] = '\0';
	}

/* Set all structure members to zero. */

	fd.m_ofn.lpstrFilter = szFilter;
	fd.m_ofn.nFilterIndex = 1;
	fd.m_ofn.lpstrFile= szFile;
	fd.m_ofn.nMaxFile = sizeof(szFile);
	fd.m_ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK | OFN_EXPLORER;


	if (fd.DoModal()==IDOK) 
	{
		namef=fd.GetPathName();
		CString namex;
		namex=fd.GetFileExt();
		if (namex.IsEmpty()) namef+=".txt";
		hf.Open(namef,CFile::typeText | CFile::modeWrite | CFile::modeCreate);
		nel=Elements.GetSize();
		for (j=0;j<TimeInt.GetSize();j++)
		{
			CTimeStep* ts=GetTime(j);
			msg.Format("Time: %f\n",ts->time);
			hf.WriteString(msg);
			msg="No.    Depth  Potential   Moisture  Conc.in fluid  Sorbed\n";
			hf.WriteString(msg);
			for (i=0;i<ts->Results.GetSize();i++)
			{
				CResult* rs=ts->GetResult(i);
				k=i;if (k==nel) k=nel-1;
				CElement* el=GetElement(k);
				z=el->z1;if (i==nel) z=el->z2;
				msg.Format ("%2d. %8.2f %10.3f %10.3f %10.3f %10.3f\n",i+1,z,rs->psi,rs->theta,rs->conc,rs->cons);
				hf.WriteString(msg);
			}
		}
		hf.Close();
	}
}
