; $Id: sample_molwt.pro,v 1.5 2006/01/10 22:17:43 jrdcopley Exp $
;###############################################################################
; LICENSE:
;  The software in this file is written by an employee of
;  National Institute of Standards and Technology
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used of if the code in this file is
;  included in another product.
;
;###############################################################################
; Written by J.R.D. Copley.
;************************************************************************************************
pro sample_molwt_cleanup,tlb
;************************************************************************************************
;
compile_opt strictarr
;
widget_control,tlb,get_uvalue=pstate
ptr_free,pstate
end


;************************************************************************************************
pro sample_molwt_handler,event
;************************************************************************************************
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
; Respond to "Done" button.
if (event.id eq (*pState).done) then begin
	widget_control,event.top,/destroy
	return
endif
;
; If an input value is modified, blank out the calculated values.
for k=1,(*pState).nrow-1 do begin
	if (event.id eq (*pState).info52[k]) then begin
		if (event.type eq 0) then begin
			if (event.ch eq 10) then break
		endif
		for kk=1,(*pState).nrow-1 do begin
			widget_control,(*pState).info53[kk],set_value=''
		endfor
		return
	endif
endfor
;
; Get chemical formulae of solute and solvent.
widget_control,(*pState).form1,get_value=formula1
widget_control,(*pState).form2,get_value=formula2
;
; Given the chemical formulae of solute and solvent, compute molecular weights
;	and chemical compositions of solute and solvent.
molwt=fltarr(2)
condense=strarr(2)
for j=1,2 do begin
	if (j eq 1) then formula=formula1
	if (j eq 2) then formula=formula2
	if (formula eq '') then break
	simplify_formula,formula,natoms,isotope
	index=sort(isotope)
	isotope=isotope[index]
	natoms=natoms[index]
	lgth=n_elements(index)
	if (lgth eq 1) then begin
		start=0
		stop=0
	endif else begin
		start=[0,where(isotope[0:lgth-2] ne isotope[1:lgth-1])+1]
		stop=[where(isotope[0:lgth-2] ne isotope[1:lgth-1]),lgth-1]
	endelse
	nent=n_elements(start)
	entry=strarr(nent)
	;
	; Loop over elements in compound
	for k=0,nent-1 do begin
		iso=isotope[start[k]]
		if (iso eq '2H') then iso='D'
		if (iso eq '3H') then iso='T'
		if (strlen(iso) gt 4) then begin
			if (strmid(iso,0,4) eq 'nat-') then iso=strmid(iso,4)
		endif
		number=total(natoms[start[k]:stop[k]])
		if (fix(number) eq number) then fmt='(i5)' else fmt='(f8.3)'
		entry[k]=iso+strcompress(string(number,format=fmt),/remove_all)
	endfor
	entry=entry[sort(entry)]
	condense[j-1]=strjoin(entry,', ')
	;
	res=where(natoms le 0.0,count)
	if (count gt 0.0) then begin
		molwt="Zero subscript not permitted"
		return
	endif
	;
	molwt[j-1]=0.0
	n=n_elements(natoms)
	atwt=fltarr(n)
	; Loop over terms in given chemical formula.
	for m=0,n-1 do begin
		z=where(' '+isotope[m] eq ((*pState).atwts).isosym,count)
		if (count ne 1) then begin
			molwt="Chemical symbol "+isotope[m]+" not found"
			return
		endif
		if (count eq 1) then begin
			atwt[m]=((*pState).atwts).isomass[z]
			molwt[j-1]=molwt[j-1]+natoms[m]*atwt[m]
		endif
	endfor
endfor
;
A1=molwt[0]
A2=molwt[1]
if (A1 eq 0.0) then return
;
; Write out molecular weights and chemical compositions.
v42=strarr(4)
v42[0]=' '+condense[0]
v42[1]=strcompress(string(A1,format='(f8.3)'))+' g/mole'
if (A2 gt 0.0) then begin
	v42[2]=' '+condense[1]
	v42[3]=strcompress(string(A2,format='(f8.3)'))+' g/mole'
endif else begin
	v42[3]=''
endelse
widget_control,(*pState).info42,set_value=v42
;
; Determine what to calculate.
if (event.id eq (*pState).what) then begin
	(*pState).dowhat=event.index
endif
;
fmt=(*pState).fmt
;
nrow=(*pState).nrow
quan=fltarr(nrow)
; Read input information.
for k=1,nrow-1 do begin
	widget_control,(*pState).info52[k],get_value=v52
	quan[k]=float(v52[0])
	if (quan[k] le 0.0) then v52='' else v52=string(quan[k],format=fmt)
	widget_control,(*pState).info52[k],set_value=v52
endfor
;
; Compute output quantities.
; quan[1] is Molality m (mole/kg)
; quan[2] is Molarity M (mole/L)
; quan[3] is Solvent density rho (g/mL)
; quan[4] is Solution density rhoprime (g/mL)
; quan[5] is Concentration in solvent conc (mg/mL)
; quan[6] is Concentration in solution cprime (mg/mL)
; quan[7] is Solute mass fraction f1
; quan[8] is Solute mole fraction g1
;
molality=quan[1]
Molarity=quan[2]
rho=quan[3]
rhoprime=quan[4]
conc=quan[5]
cprime=quan[6]
f1=quan[7]
g1=quan[8]
;
quan=strarr(nrow)
case (*pState).dowhat of
;
	-1: (*pState).dowhat=0
;
; Given m, rho, A1, A2, calculate conc, f1, g1.
	0: begin
		if (molality gt 0.0 and rho gt 0.0) then begin
			conc=A1*molality*rho
			f1=conc/(conc+1000*rho)
			g1=f1*A2/(f1*A2+(1.0-f1)*A1)
			quan[5]=conc
			quan[7]=f1
			quan[8]=g1
		endif
	end
;
; Given conc, rho, calculate m, f1, g1.
	1: begin
		if (conc gt 0.0 and rho gt 0.0) then begin
			molality=conc/(A1*rho)
			f1=conc/(conc+1000*rho)
			g1=f1*A2/(f1*A2+(1.0-f1)*A1)
			quan[1]=molality
			quan[7]=f1
			quan[8]=g1
		endif
	end
;
; Given M, calculate cprime.
	2: begin
		if (Molarity gt 0.0) then begin
			cprime=Molarity*A1
			quan[6]=cprime
		endif
	end
;
; Given cprime, calculate M.
	3: begin
		if (cprime gt 0.0) then begin
			Molarity=cprime/A1
			quan[2]=Molarity
		endif
	end
	else:
endcase
;
for k=1,nrow-1 do begin
	if (quan[k] le 0.0) then v53='' else  v53=strcompress(string(quan[k],format=fmt))
	widget_control,(*pState).info53[k],set_value=v53
endfor
end



;************************************************************************************************
pro sample_molwt,$
	group_leader = group_leader,$
	notify_ids = notify_ids,$
	register_name = register_name
;************************************************************************************************
;
; Depending what it knows, this routine returns quantities such as molecular weight,
;	concentration, mass fraction, etc.
compile_opt strictarr
;
if n_elements(group_leader) eq 0 then group_leader = 0L
if n_elements(notify_ids) eq 0 then notify_ids = [0L,0L]
if n_elements(register_name) eq 0 then register_name = 'concentrations'
;
; If this procedure is already running, return.
if xregistered(register_name) then return
;
defsysv,'!atwts',exists=exists
if (exists) then begin
	atwts=!atwts
	labels=!labels
endif else begin
	progressBar = Obj_New("SHOWPROGRESS",xsize=220,ysize=2,$
		message="Reading atomic weight information; please wait.")
	progressBar->Start
	getfromWeb=1
	readAtWeights,atwts,labels,getfromWeb=getfromWeb
	progressBar->Destroy
	Obj_Destroy, progressBar
	if (getfromWeb lt 0) then return
	defsysv,'!atwts',atwts
	defsysv,'!labels',labels
endelse
;
; Default formulae.
formula1='CH2CH3-(OCH2CH2)29-OCH2CH3'; this is PEO.
formula1='(CD3)2CDCD2CD(NHCOCD3)CONHCD3'; this is NALMA.
formula2='H2O'; we all know what this is.
;
v41=strarr(4)
v41[0]='Solute composition'
v41[1]='Solute molecular weight A1'
v41[2]='Solvent composition'
v41[3]='Solvent molecular weight A2'
;
nrow=9
v51=strarr(nrow)
v51[0]='QUANTITY'
v51[1]='Molality m (mole/kg)'
v51[2]='Molarity M (mole/L)'
v51[3]='Solvent density rho (g/mL)'
v51[4]='Solution density rhoprime (g/mL)'
v51[5]='Concentration in solvent c (mg/mL)'
v51[6]='Concentration in solution cprime (mg/mL)'
v51[7]='Solute mass fraction f1'
v51[8]='Solute number fraction g1'
;
quan=fltarr(nrow)
quan[1]=0.5
quan[3]=1.0
;
fmt='(g10.5)'
;
v52=strarr(nrow)
v52[0]='INPUT VALUE'
for k=1,nrow-1 do begin
	if (quan[k] gt 0.0) then v52[k]=string(quan[k],format=fmt)
endfor
;
v53=strarr(nrow)
v53[0]='CALCULATED VALUE'
;
choices=         'Given m, rho and A1, calculate c and f1; also given A2, calculate g1.'
choices=[choices,'Given c, rho and A1, calculate m and f1; also given A2, calculate g1.']
choices=[choices,'Given M and A1, calculate cprime.']
choices=[choices,'Given cprime and A1, calculate M.']
;
frame=0
wid_info1=35
wid_info2=18
wid_info3=18
;
tlb=widget_base(/col,title='Molecular weights and concentrations')
	row1=widget_base(tlb,/row)
		form1=cw_field(row1,/string,value=formula1,/col,$
			title='Chemical formula of solute',/return_events,frame=frame)
	row2=widget_base(tlb,/row)
		calc=widget_button(row2,value='Calculate')
		form2=cw_field(row2,/string,value=formula2,/col,$
			title='Chemical formula of solvent',/return_events,frame=frame)
		done=widget_button(row2,value='Done')
	row3=widget_base(tlb,/row)
		what=widget_combobox(row3,value=choices)
	row4=widget_base(tlb,/row)
		info41=widget_text(row4,xsize=wid_info1,ysize=4,value=v41)
		info42=widget_text(row4,xsize=wid_info2+wid_info3+2,ysize=4,value=v42)
	row5=widget_base(tlb,/col)
		base5=lonarr(nrow)
		info51=lonarr(nrow)
		info52=lonarr(nrow)
		info53=lonarr(nrow)
		for k=0,nrow-1 do begin
			base5[k]=widget_base(row5,/row)
			info51[k]=widget_text(base5[k],xsize=wid_info1,value=v51[k])
			info52[k]=widget_text(base5[k],xsize=wid_info2,value=v52[k],$
				editable=(k gt 0),/all_events)
			info53[k]=widget_text(base5[k],xsize=wid_info3,value=v53[k])
		endfor
;
geom=widget_info(row4,/geometry)
done_geom=widget_info(done,/geometry)
calc_geom=widget_info(calc,/geometry)
widget_control,form1,xsize=geom.xsize
widget_control,form2,xsize=geom.xsize-1.1*(done_geom.xsize+calc_geom.xsize)
widget_control,what,xsize=geom.xsize
centertlb,tlb
widget_control,tlb,/realize
;
state={$
	done:done,$
	calc:calc,$
	form1:form1,$
	form2:form2,$
	what:what,$
	info41:info41,$
	info42:info42,$
	info51:info51,$
	info52:info52,$
	info53:info53,$
	formula:'',$
	dowhat:-1,$
	fmt:fmt,$
	isotope:strarr(20),$
	atwt:fltarr(20),$
	molwt:0.0,$
	atwts:atwts,$
	nrow:nrow,$
	v52_prev:v52}
pState=ptr_new(state)
widget_control,tlb,set_uvalue=pState
sample_molwt_handler,{top:tlb,id:calc,handler:tlb}
xmanager,register_name,/no_block,tlb,cleanup='sample_molwt_cleanup',$
	event_handler='sample_molwt_handler'
end
