#
#	titration3.d 
#	three analytes
#	Given: Sample mg or Aliquot, W% of analytes
#	23 May 2002 by ES
#

import "math"
import "gui"

w   = gui.window("Acid-Base Titrations (up to three analytes), pH(v) and buffer intensity", [0,0,680,500])
p   = gui.pane(w, [220,20,620,420], {border: 'sunken})
q   = gui.button(w, "How to..", [30,280,190,380], {font:{name:"Arial", size: 200}})
b2  = gui.button(w, "Titration", [75, 430, 165, 460], {font:{name:"Arial", size: 140}})
b3  = gui.button(w, "Overlay of two titrations", [250, 430, 460, 460], {font:{name:"Arial", size: 140}})
b4  = gui.button(w, "Done" , [480, 430, 570, 460], {font:{name:"Arial", size: 140}})
la  = gui.label(w, "Analytes", [10,13,59,35])
ra  = gui.edit (w, "HNO3, H3PO4, CH3COOH", [60,10,196,32])
lsam= gui.label(w, "Sample mg:", [10,43,77,65])
qsam= gui.edit (w, "583.7/5", [83,40,140,62])
lra = gui.label(w, "pK1:", [10, 73, 30, 95])
qa1 = gui.edit (w, "-1.32", [37, 70, 84, 92])
qa2 = gui.edit (w, "2.12", [93, 70, 140, 92])
qa3 = gui.edit (w, "4.76", [149, 70, 196, 92])
lrb = gui.label(w, "pK2:", [10, 103, 49, 125])
qb1 = gui.edit (w, "0.0", [37, 100, 84, 122])
qb2 = gui.edit (w, "7.22", [93, 100, 140, 122])
qb3 = gui.edit (w, "0.0", [149, 100, 196, 122])
lrc = gui.label(w, "pK3:", [10, 133, 49, 155])
qc1 = gui.edit (w, "0.0", [37, 130, 84, 152])
qc2 = gui.edit (w, "12.36", [93, 130, 140, 152])
qc3 = gui.edit (w, "0.0", [149, 130, 196, 152])
lrv = gui.label(w, "C%:", [10, 163, 49, 185])
qv1 = gui.edit (w, " 2.47", [37, 160, 84, 182])
qv2 = gui.edit (w, "72.76", [93, 160, 140, 182])
qv3 = gui.edit (w, "12.30", [149, 160, 196, 182])
lrk = gui.label(w, "M:", [10, 193, 49, 215])
qk1 = gui.edit (w, "63.01", [37, 190, 84, 212])
qk2 = gui.edit (w, "98.00", [93, 190, 140, 212])
qk3 = gui.edit (w, "60.05", [149, 190, 196, 212])
lrt = gui.label(w, "Ct:", [10, 253, 49, 275])
qt  = gui.edit (w, "0.1", [37, 250, 84, 272])
lru = gui.label(w, "V0:", [117, 253, 140, 275])
qu  = gui.edit (w, "20.0", [149, 250, 196, 272])
lrn = gui.label(w, "np:", [10, 223, 49, 245])
qn1 = gui.edit (w, "1", [37, 220, 84, 242])
qn2 = gui.edit (w, "3", [93, 220, 140, 242])
qn3 = gui.edit (w, "1", [149, 220, 196, 242])
rad1 = gui.radio(w, "Alkalimetric", [75,390,195,408])
rad2 = gui.radio(w, "Acidimetric ", [75,410,165,428])


# global declarations
	rad1.checked = true
	pk1 = array(3)
	pk2 = array(3)
	pk3 = array(3)
	k   = [[1.0,2.0,3.0],
			[4.0,5.0,6.0],
			[7.0,8.0,9.0]]
	kh  = [[1.0,2.0,3.0],
			[4.0,5.0,6.0],
			[7.0,8.0,9.0]]
	v0 = 0.0
	weight = 0.0
	perc = array(3)
	mw = array(3)
	ca = array(3)
	np = array(3)
	u = array(560)
	v = array(560)
	t = array(560)
	zm = 1
	kw = 1.0e-14
	data = array(22)
	name = ""
	vv = 0.0;
	ct = 0.0; n0 = 0; n1 = 0
	ih = 352; ph = 0.0; h = 0.0; oh = 0.0
		


getData = func()
	return [ra.text, qsam.text,float(qa1.text), float(qa2.text),\
			float(qa3.text),float(qb1.text),float(qb2.text),\
			float(qb3.text),float(qc1.text),float(qc2.text),\
            float(qc3.text),float(qv1.text),float(qv2.text),\
			float(qv3.text),float(qk1.text),float(qk2.text),\
            float(qk3.text),float(qt.text),float(qu.text),\
			int(qn1.text),int(qn2.text),int(qn3.text)]
endfunc

# Initialize 
p.start = func()
	local i
	data = getData()
    name = data[1]
	weight = eval(data[2])
	for i = 1 to 3
		pk1[i] = data[2+i]
		pk2[i] = data[5+i]
		pk3[i] = data[8+i]
		perc[i] = data[11+i]
		mw[i]  = data[14+i]
		np[i]  = data[19+i]
	endfor
	ct = data[18]
	v0 = data[19]
endfunc

rad1.onclick = func()
	zm = 1
endfunc

rad2.onClick = func()
	zm = 2
endfunc

q.onclick = func()
	print "   This program simulates an exact titration curve", cr
	print "   as it would be measured with a pH titrator under", cr
	print "   the given conditions. You may choose alkalimetric", cr
	print "   (default) or acidimetric titration.- Data fields:", cr
	print "   1) For analytes:", cr
	print "   - Sample weight in mg, or an Aliquot e.g. 583.7/5", cr
	print "   - pK1, pK2, pK3 (zero for non existing steps)", cr
	print "   - Weight percent for each Component C%", cr
	print "   - Molecular mass M", cr
	print "   - Number of protons per molecule np", cr
	print "   2) Concentration (titer) Ct mol/L of titrator", cr
	print "   3) Starting solution volume V0 ml of the analytes.-", cr
	print "   Now click 'Titration' to generate the curve.", cr
	print "   If necessary, adjust Ct to fit the curve into the", cr
	print "   given frame.", cr
	print "   The buffer intensity (points) shows the quality of", cr
	print "   titration points (sharper = better).", cr
	print "   Click 'Overlay..' to superimpose a second curve", cr
	print "   on the first one, e.g. to see the effect of changing", cr
	print "   any data values.", cr
	print "   Try alkalimetric titration and then overlay with", cr
	print "   acidimetric titration of deprotonated species.", cr  
endfunc

p.grid = func()
    local i, ix, iy
	p.pen = {width: 4, color: [255,255,255]}
	for i = 1 to 90
		p.DrawLine(i*4+38,384-22,i*4+38,384-ih)
	endfor 
	p.pen = {color: [128,128,196]}
	for i = 1 to 12
		p.DrawLine(30*i+10,384-17,30*i+10,384-ih)
	endfor
	for i=1 to 14
		p.DrawLine(37,388-24*i,400,388-24*i)
	endfor
#	p.pen = {width:1, color: [255,255,0]}
	for i = 0 to 11
		ix = 30*(i+1)+7
		if i >= 5 then
			ix = ix - 3
		endif
		p.DrawText(ix,370,2*i)
	endfor
	p.DrawText(20,24,"pH")
	for i = 0 to 13
		iy = 24*(i+1)
		ix = 28
		if i >= 10 then ix = 20; endif
		p.DrawText(ix,380-iy,i)
	endfor
	p.pen = {color: [0,0,255]}
	p.DrawText(260,383,"Titrator  ml")
endfunc

p.curve = func()
	local st,d,i,ii,ix,iy,ix1,ix2,v1,vw,vn,dv,first
	first = true
	st = 0.025
	for i=1 to 3
		ca[i] = weight*perc[i]/mw[i]/v0/100
	endfor
	for i=1 to 3
		if np[i] = 1 then
			k[1][i] = pk1[i]
			if zm=2 then k[1][i] = 14.0 - pk1[i]; endif
			kh[1][i] = math.pow(10,k[1][i])
		elseif np[i] = 2 then
			k[1][i] = pk2[i]
			k[2][i] = pk1[i]
			if zm=2 then
				k[1][i] = 14.0 - pk1[i]
				k[2][i] = 14.0 - pk2[i]
			endif
			kh[1][i] = math.pow(10,k[1][i])
			kh[2][i] = kh[1][i]*math.pow(10,k[2][i])
		elseif np[i] = 3 then
			k[1][i] = pk3[i]
			k[2][i] = pk2[i]
			k[3][i] = pk1[i]
			if zm=2 then
				k[1][i] = 14.0 - pk1[i]
				k[2][i] = 14.0 - pk2[i]
				k[3][i] = 14.0 - pk3[i]
			endif
			kh[1][i] = math.pow(10,k[1][i])
			kh[2][i] = kh[1][i]*math.pow(10,k[2][i])
			kh[3][i] = kh[2][i]*math.pow(10,k[3][i])
		endif
	endfor
	for ii = 0 to 560
		ph = st*ii
		h = math.pow(10,-ph)
		oh = kw/h
		v1 = vv
		vv = 0.0
		for i = 1 to 3
			if np[i] = 1 then
				d = 1+h*kh[1][i]
				vw = v0*(oh-h+ca[i]/d)
			elseif np[i] = 2 then
				d = 1+h*(kh[1][i]+h*kh[2][i])
				vw = v0*(oh-h+ca[i]*(2+h*kh[1][i])/d)
			elseif np[i] = 3 then
				d = 1+h*(kh[1][i]+h*(kh[2][i]+kh[3][i]*h))
				vw = v0*(oh-h+ca[i]*(3+h*(2*kh[1][i]+h*kh[2][i]))/d)
			else vw = 0.0
			endif
			vv = vv + vw
		endfor
		vv = vv/(ct+h-oh)
		if vv > 23.0 then 
			n1 = ii
			break
		endif
		ix = math.round(15*vv+40)
		if zm = 1 then
			iy = math.round(24*ph+20)
		elseif zm = 2 then
			iy = math.round(24*(14.0-ph)+20)
		endif
		if vv >= 0 then
			if first then
				n0 = ii
				x1 = 40
				y1 = 384 -iy
				first = false
			else
				x1 = ix1
				y1 = 384 - iy1
			endif
			p.pen ={width: 2, color: [255,0,0]}
			p.DrawLine(x1,y1,ix,384-iy)
			u[ii+1] = x1; v[ii+1] = y1
			ix1 = ix; iy1 = iy
			dv = (vv - v1)/st*0.1
			iy = math.round(380*dv+20)
			t[ii+1] = 384-iy
			if iy < 350 then
				p.pen = {width: 1, color: [255,128,128]}
				p.DrawLine(ix,384-iy,ix,384-iy-1)
			endif
		endif	
	endfor
	n1 = ii - 1
endfunc


#Titration
b2.onclick = func()
	p.start()
	p.onPaint = func()
		p.grid()
		p.curve()
	endfunc
	p.rePaint()
endfunc

# Overlay of second titration curve
b3.onclick = func()
	local ii, x1, y1
	p.onPaint = func()
		p.grid()
		x1 = u[n0+1]
		y1 = v[n0+1]
		for ii = n0+2 to n1-1
			p.pen = {width:2, color: [128,128,255]}
			p.DrawLine(x1,y1,u[ii],v[ii])
			if t[ii] > 34 then
				p.pen = {width:1, color: [156,156,255]}
				p.DrawLine(x1,t[ii],x1,t[ii]-1)
			endif
			x1 = u[ii]; y1 = v[ii]
		endfor		
		p.start()
		p.curve()
	endfunc
	p.rePaint()
endfunc
	
b4.onclick = func()
	w.close()
endfunc	

gui.enter()

