Learning Activity Modules in Chemical Engineering using webMathematica

Phase equilibria, activity coefficients, and their application in binary distillation

Brian G. Higgins
University of California, Davis
bghiggins@ucdavis.edu

Abstract

Computing vapor-liquid equilibria  is a common occurrence in many chemical engineering operations. For ideal mixtures the calculations are fairly routine. Unfortunately, many vapor liquid systems of industrial interest form non-ideal mixtures and the calculations then require solving systems of nonlinear equations. In this presentation we show how webMathematica can be used to develop a online site that students can use to validate VLE models using their own experimental data. For the purpose of this talk, the vapor phase is taken to be an ideal gas mixture, but the liquid phase is non-ideal  Thus at equilibrium the equality of fugacities for n species yields the following equilibrium relations

(Subscript[y, i]) 
          (Subscript[P, total]) = (Subscript[γ, i]) (Subscript[x, i]) (Subscript[P, i]^sat) (T), i = 1, 2,  …, n

where (Subscript[y, i]) is the mole fraction of species i in the vapor phase; (Subscript[x, i ])is the mole fraction of species i in the liquid phase; (Subscript[γ, i])is the activity coefficient for species i; (Subscript[P, i]^sat) (T) is the saturation vapor pressure of species i at temperature T;  and (Subscript[P, total]) is the total pressure of the system.

Because the activity coefficients depend on composition, and the vapor pressures depend on T, virtually all calculations of vapor-liquid data for such a system involves solving nonlinear equations. In this presentation we illustrate how VLE calculations (for binary systems) can be done over the World Wide Web using webMathematica.

We make use of several open source applications to build our interactive site using webMathematica. We use the Tomcat servelet engine, Apache server, PHP scripting language, and MYSQL. The MYSQL database is used to store thermodynamic data on a wide variety of chemical compounds, and to hold user IDs/passwords for site authentication. We have developed a system, based on hidden frames and JavaScript that allows us to interface  PHP and MSP so that thermodynamic data from database can be used in the online Mathematica calculations.

The interactive site allows users to select  Margules, van Laar or Wilson models for the activity coefficients and Antoine's correlation for the vapor pressure. The user can select to make bubble point and dew point calculations, construct T-x-y, P-x-y, and x-y plots of the data, and also undertake best-fit calculations for activity parameters based on VLE data, which can be uploaded to the site. Azeotropes feature prominently in these calculations.

Introduction

Background

(i)  Web technology in education is pervasive: from static web pages to online classes.
There is however a definite need for more dynamic content . In engineering this often means having the ability to do computations dynamically based on user input.

(ii) Early efforts for dynamic calculations involved Java Applets, known as client-side technology. Not very successful; very dependent on clients computer configuration.

(iii) In recent years effort has moved to do computations on the server-side (e.g. Java servlets). Advantages of server-side technology is it is likely to perform as designed. User's interface is a conventional browser.

(iv) The trend in industry is to move increasingly toward web-based engineering design/computations.

Objectives

"Chemical engineering is the synthesis and design of chemical processes that result in the transformation of matter by chemical reaction resulting in new chemicals and/or products."

Mathematical and computer assisted analysis is used throughout the chemical engineering prpgram at UC Davis. Sophomore students are required to take a course in Fortran or Matlab programming.  We have also  introduced the students (juniors/seniors) to Mathematica as an alternative platform for doing computations. We offer an introductory course twice a year on Mathematica.

Challenge is to expose students to more real-life problems: web-based computations seems ideally suited for this purpose.

A beta user's experiences with webMathematica

Setting up webMathematica on Windows NT/2000

Overall I found the documentation helpful. Tricky part was setting all the PATHS and CLASSPATHS and init files for the various servers. First time it took about 2-3 hours, starting from scratch, to set up all the servers for my system (see below) and run a webMathematica example. New version of Mathematica with built-in Java SDK should simplify installation.

Configuration

Web server: Apache1.3.20
	Servlet container: Tomcat 3.2.3
	Database: MYSQL 3.23.41 (JDBC driver: mm.mysql 2.04)
	Java: JDK 1.3.1
	JLink: 1.1.2
	Web page scripting languages:
		Server-side: webMathematica 0.93, PHP 4.06
		Client-side: JavaScript

I have integrated Apache with Tomcat using the mod jk server adapter. With this configuration all html/php files are served by Apache, while msp and jsp pages are served by Tomcat using the same port.

Designing interactive modules using webMathematica: User interface

Straightforward to design a user interface (using form elements) with a few inputs that result in a single outcome. Here is an example (link)

plot1D.msp

<html>
	<head>
	<script language="JavaScript">
	function myfunc(data){
	page="Plot1DOut";
	
	if(data.f1.value){
	myf1=escape(data.f1.value);
	myregExp="+";
	for(i=1;i<5;i++){myf1=myf1.replace(myregExp,"%2B")};
	myf2=myf1;
	}
	else{
	myf2=0;
	}
	myregExp="+";
	myf=escape(data.f.options[data.f.selectedIndex].value);
	for(i=1;i<5;i++){myf=myf.replace(myregExp,"%2B")};
	myf3=myf;
	
	
plotWindow=window.open(page+'.msp?f1='+myf2+'&f='+myf3+'&xmin='+escape(data.xmin.value)+'&xmax='+escape(data.xmax.value),'mywindow','width=450,height=400,toolbar=no,location=yes,scrollbars=yes,menubar=yes,left=300,top=0');
plotWindow.focus();
}
function newWindow(){
window.open('/Instructions/help.html','mywindow2','width=550,height=300,toolbar=no,scrollbars=yes,menubar=no,left=200,top=0');
}
	
	</script>
		
	
		<meta name=generator content=Adobe GoLive 4>
		<title>PlotInputData</title>
	</head>

	<body bgcolor=white>
		<center>
			<h3>Plot Your Function <font color=blue size=4>f(x):</font></h3>
		</center>
		<div align=left>
			<p><font color=black>This site displays a graphical representation of 
			a user-supplied function. You may select some built-in functions, or else
			 specify your own function <b>f(x).</b> You may also select the range of
			  the variable <b>x</b> to be displayed in the plot.
			<form name=myPlot>
			<br>
			</font></p>
			
			<table cellpadding=0 cellspacing=2>
			<td><font color=black><b>f(x)=</b></font></td>
					<td><Select name=f>
					<option value="<%Mathlet MSPValue[ $$f,  "Sin[x]"] %>">Sin[x]
					<option value="<%Mathlet MSPValue[ $$f,  "Cos[x]"] %>">Cos[x]
					<option value="<%Mathlet MSPValue[ $$f,  "Exp[x]"] %>">Exp[x]
					<option value="<%Mathlet MSPValue[ $$f,  "Tan[x]"] %>">Tan[x]
					<option value="<%Mathlet 
					MSPValue[ $$f,  "Exp[-0.3x]Sin[x]"] %>">Exp[-0.3x]Sin[x]
					<option value="<%Mathlet MSPValue[ $$f,  "x^2-3x-10"] %>">quadratic
					<option value="<%Mathlet MSPValue[ $$f,  "x^3-5x^2-5x+10"] %>">cubic
					
					</Select></td>
				<tr>
				</table>
				<br>or else specify your own function
				 ( access this<A HREF="Javascript:newWindow()"> guide</a>
				  to get help on entering a function )
				<p></p>
				<table cellpadding=0 cellspacing=2>
				<tr>
					<td><font color=black><b>f(x)=</b></font></td>
					
					<td><input type=text name=f1 size=33 value=""></td>
				</tr>
			</table>
		<br>
			Enter the plot range for the variable <b>x</b><br>
			</p>
			<p><font color=blue size=5>
			<table border=0 cellpadding=0 cellspacing=2 bgcolor=white>
				<tr>
					<td><font color=black><b>Xmin=</b></font></td>
					<td><input type=text name=xmin size=3 value=
					"<%Mathlet MSPValue[ $$xmin,  "0"] %>"></td>
					<td><font color=black><b>Xmax=</b></font></td>
					<td><input type=text name=xmax size=3 value=
					"<%Mathlet MSPValue[ $$xmax,  "2Pi"] %>"></td>
				</tr>
			</table>
			<br>
			</font><input type=button value=Evaluate onclick="myfunc(this.form)"></p>
			<p><font color=black>The plot will be shown in a new window.</font></p>
		</div>
		<p>
		</form>
		<p>
		<FORM ACTION="Plot" METHOD="POST">
			<INPUT TYPE="button" VALUE="Close" onClick="window.close()">
			</FORM>
			</p>
	</body>

</html>

Plot1dOut.msp

<html>

	<head>
		<meta name=generator content=Adobe GoLive 4>
		<title>Plot1DOutput</title>
	</head>

	<body bgcolor=white>
		<center>
			<h3>Here is the function <font color=blue><b>f(x)</b></font> you requested</h3>
			<%Mathlet MSPBlock[{$$f,$$f1},myf=f2/.f2->If[$$f1==0,
			$$f,$$f1,$$f1];MSPFormat[f[x]==myf,TraditionalForm]]%>
		</center>
		<div align=Center>
		<P>
			<%Mathlet MSPBlock[ {$$f,$$xmin,$$xmax,$$f1},
		MSPShow[Plot[f2/.f2->If[$$f1==0,$$f,$$f1,$$f1], {x,$$xmin,$$xmax},
		PlotRange->All,PlotStyle->RGBColor[0,0,1],
		AxesLabel->{"x","f(x)"},ImageSize->300]]]%>
</p>
<p>
			<FORM ACTION="Plot" METHOD="POST">
			<INPUT TYPE="button" VALUE="Close" onClick="window.close()">
			</FORM>
			</p>
		</div>
	</body>

</html>

Challenge is to design a user interface with multiple options that allow "what if" decisions, with multiple outcomes; use of  nested forms, form input validation, multiple windows, frames, and database connectivity.

Requires a solid foundation in web technology.

What is the appropriate user interface for learners versus end-users?

Example 1:

This example shows how one can integrate webMathematica into an online course environment. The link below is a proposed prototype for Advanced Placement Calculus course The investigators on the project were B. G. Higgins, E.Milton, E Silvia from UC Davis.

Interactive modules for APCalculus prototype

Units 2, 6, & 7 in the above link have webMathematica examples.

Programs for AP Calculus module

ApproxSum.msp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
		
	<title>Approximating Sums</title>
	<script language="JavaScript">
	function myfunc(data){
		var page="ApproxSumOut";
		myM=escape(data.m1.options[data.m1.selectedIndex].value);
		myKey=escape(data.key.options[data.key.selectedIndex].value);
	myregExp="+";
	myf=escape(data.f.options[data.f.selectedIndex].value);
	for(i=1;i<5;i++){myf=myf.replace(myregExp,"%2B")};
	myf3=myf;
	
	
plotWindow=window.open(page+'.msp?f='+myf3+'&a='+escape(data.a.value)+'&b='+escape(data.b.value)+'&n='+escape(data.n.value)+'&m='+escape(data.m.value)+'&m1='+myM+'&key='+myKey,'mywindow','width=450,height=450,toolbar=no,location=no,scrollbars=yes,menubar=no,left=300,top=0');
plotWindow.focus();
}
function sideBar2Window(data){
		var sidepage=data;
		sideBar2Window7_4_2=window.open(sidepage,'mywindow4','width=500,height=400,toolbar=no,scrollbars=yes,menubar=no,left=100,top=0');
		}
// -->
		</script>
	<meta name="generator" content="BBEdit 6.0">
</head>
<body>
<Center><h2><font color=blue> Approximating the area under a non-negative function</font></h2></center>
In this interactive session you will examine how refining the partition of a domain affects the computed area under the curve <b>f(x)</b>
using the method of approximating sums as discussed in Lesson 6.2<br>
<p>
<form name=pram>
Select one of three functions to consider
			
			<p></p>
			<br><table cellpadding=0 cellspacing=2>
				<tr>
					<td><font color=black><b>f(x)=</b></font></td>
					<td><Select name=f>
					<option value="<%Mathlet MSPValue[ $$f,  "1.2 + Exp[-.4t]Cos[3t]"] %>">2 + exp(-.4x)cos(3x)
					<option value="<%Mathlet MSPValue[ $$f,  "2+Sin[t]"] %>">2+sin(x)
					<option value="<%Mathlet MSPValue[ $$f,  "Log[t+(t^2+1)^(1/2)]"] %>">ln(x+(x^2+1)^(1/2))
					
					
					</Select></td>
					
					</tr>
				</table> 
				</p>
In the form below enter the relevant parameters for your calculation.

Enter the domain for your function (<b>a>0</b>):
<table>
<tr
<td><b> a=</b></td>
<td><input type="text" name="a" value="0" size="6"></td>
<td><b> b=</b></td>
<td><input type="text" name="b" value="2" size="6"></td>
</tr>
</table>
<br>
Enter the number of interior points in your initial partition(<b>0 &lt n &lt 6</b>), and select
 the location <b>c<sub>i</sub></b> for evaluating your function: left end point, interior point, or right end point:<br>
<table border="0" cellpadding="3" cellspacing="3" width="241">
						<tr>
							<td><b>n=</b></td>
							<td><input type="text" name="n" value="3" size="6"></td>
							<td><select name="m1" size="1">
									<option value="3">Left End Point
									<option value="1">Interior Point
									<option value="2">Right End Point
								</select></td>
						</tr>
					</table>
<br>
<p>Select how you would like sample points chosen - randomly by the system or equally spaced.
If you choose them randomly, points can tend to "bunch up" and cause problems for the approximation,
 so you might watch for this and for the effects.
 <p></p>
 <table cellpadding=0 cellspacing=2>
<tr>
							<td><b>Sample Points </b></td>
							
							<td><select name="key" size="1">
									<option value="1">Equally Spaced
									<option value="50">Random Assignment
									
								</select></td>
						</tr>
					</table>

<p>Finally, select the number of refinements m</a> (<b>0&lt m &lt 10</b>)
you would like of your partition. Keep in mind that each refinement effectively doubles the number of points, so you may wish to 
step gradually through an increasing number of refinements. For more details on how the refinement is done, click <A HREF="javascript:sideBar2Window('http://localhost/ApCalculus/Unit6/Lesson2/meshnotes.html')"> here</a>
</p><p></p>
<table cellpadding=0 cellspacing=2>
<tr>
							<td><b>m=</b></td>
							<td><input type="text" name="m" value="2" size="6"></td>
							
						</tr>
					</table>
<br>A plot of the function you selected will be shown in a new window.
		<table cellpadding=0 cellspacing=2>
				<tr><p>	
					<td><input type=button value=Evaluate onclick="myfunc(this.form)"></td>
					</p></tr>
					</table>
			</form>
			<p></p>
			<center>
<p><input type="button" value="Close Window" onclick="window.close()"></center>

</body>
</html>

ApproxSumOut.msp

<%Mathlet Get["RiemannSum.m"] %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
	<title>Results</title>
	

	<meta name="generator" content="BBEdit 6.0">
</head>
<body>
<center> <h2> Approximating the area under the curve</h2></center>
<%Mathlet MSPBlock[{$$a,$$b,$$n,$$m}, If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,"","<center><font color=red>Your parameters are not within the specifications. Please check</font></center>"]]%>
<center>Your initial grid based on the random number you selected is shown below:
<p></p>

<center><%Mathlet MSPBlock[{$$a,$$b,$$n,$$m,$$key},If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,MSPShow[myPartition[$$a,$$b,$$n,$$m,$$key][[1]]],""]]%></center>
<br>

The approximate area under the curve based on your initial grid is shown schematically below for the selected function <b>f(x)</b> using <%Mathlet MSPBlock[{$$m1},Switch[$$m1,1," an interior point",2,"a right end point",3,"a left end point",_,"an interior point"]]%> for function evaluation.
<p></p>

<center><%Mathlet MSPBlock[{$$a,$$b,$$n,$$m,$$key,$$m1,$$f},If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,MSPShow[myintegral[myPartition[$$a,$$b,$$n,$$m,$$key][[3]],myPartition[$$a,$$b,$$n,$$m,$$key][[4]],$$f,$$m1]],""]]%></center>
<br>
The  computed area under the curve based on your initial partition is <%Mathlet MSPBlock[{$$a,$$b,$$n,$$m,$$key,$$m1,$$f},If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,ToString[InputForm[RiemannSum[$$f, myPartition[$$a, $$b, $$n, $$m, $$key], 0, $$m1]]]<> " square units.<br>",""]]%> 

<p></p>The approximate area under the curve based on <%Mathlet ToString[$$m]%> grid refinements is shown schematically below:
<p></p>
<center><%Mathlet MSPBlock[{$$a,$$b,$$n,$$m,$$key,$$m1,$$f},If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,MSPShow[myintegral[myPartition[$$a,$$b,$$n,$$m,$$key][[5]],myPartition[$$a,$$b,$$n,$$m,$$key][[6]],$$f,$$m1]],""]]%></center>
<p></p>The computed area under the curve based on <%Mathlet If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,ToString[$$m],""]%>  grid refinements is <%Mathlet MSPBlock[{$$a,$$b,$$n,$$m,$$key,$$m1,$$f},If[mytest[{$$a,$$b,$$n,$$m},{$$n,$$m,$$b},{$$n+4,$$m},{$$a},{$$n,$$m}]>0,ToString[InputForm[RiemannSum[$$f, myPartition[$$a, $$b, $$n, $$m, $$key], 2, $$m1]]]<> " square units.<br>",""]]%> 
<p>The numerically accurate area is <%Mathlet MSPBlock[{$$a,$$b,$$f},ToString[InputForm[NIntegrate[$$f,{t,$$a,$$b}]]]<>" square units."]%>
</center>
<p></p>
<center>
<p><input type="button" value="Close Window" onclick="window.close()"></center>

</body>
</html>

RiemanSum.m

mytest[numList_, gtList_, ltList_, geList_, intList_] := 
  If[Apply[And, Map[NumberQ[#] &, numList]] && 
      Apply[And, Map[Greater[#, 0] &, gtList]] &&
      Apply[And, Map[Less[#, 10] &, ltList]] &&
      Apply[And, Map[IntegerQ[#] &, intList]] &&
      Apply[And, Map[GreaterEqual[#, 0] &, geList]], 1, 0, 0]
      
    
   myPartition[a_, b_, n_, m_, key_] := 
    Module[{mydata, xsi, Initialxsi, myInitialData, plt1, plt2, i, f1, f2, f3,
         x1, x2}, SeedRandom[key];
      f1[{x1_, x2_}] := {(x2 + x1)/2, (x2 + x1)/2};
      f2[{x1_, x2_}] := Random[Real, Sort[{x1, x2}{1., 1.}]];
      f3[{x1_, x2_}] := 
        Sort[{(x2 + x1)/2(1 - .2N[(b - a)/n]), (x2 + x1)/
                2(1 + .2N[(b - a)/n])}];
      myInitialData = 
        If[key == 1, Range[a, b, N[(b - a)/(n+1)]], 
          Sort[Prepend[
              Append[Map[Random[Real, #] &, 
                  Partition[Range[a, b, N[(b - a)/(n)]], 2, 1]], b], a]]];
      Initialxsi = 
        If[key == 1, Map[First[f1[#]] &, Partition[myInitialData, 2, 1]], 
          Map[f2[#] &, Partition[myInitialData, 2, 1]]];
      InitialDeltaX = 
        Flatten[Partition[myInitialData, 2, 1] /. {x_, y_} -> {y - x}];
      plt1 = 
        Plot[0, {t, a, b}, Axes -> {True, False}, PlotRange -> {{-.1,1.02b},Automatic}, 
          Epilog -> {{RGBColor[1, 0, 0], PointSize[0.02], 
                Map[Point[{#, 0}] &, myInitialData]}, {RGBColor[0, 0, 1], 
                PointSize[0.02], Map[Point[{#, 0}] &, Initialxsi]}}, 
          DisplayFunction -> Identity];
      mydata = myInitialData;
      xsi = Initialxsi;
      For[i = 1, i < m + 1, i++, mydata = Sort[Join[mydata, xsi]];
        xsi = Map[Random[Real, f1[#]] &, Partition[mydata, 2, 1]]];
      plt2 = 
        Plot[0, {t, a, b}, Axes -> {True, False}, PlotRange -> {{-.1,b+.5},Automatic}, 
          Epilog -> {{RGBColor[1, 0, 0], PointSize[0.02], 
                Map[Point[{#, 0}] &, mydata]}, {RGBColor[0, 0, 1], 
                PointSize[0.02], Map[Point[{#, 0}] &, xsi]}}, 
          DisplayFunction -> Identity];
      result = {Show[plt1, DisplayFunction -> $DisplayFunction], 
          Show[plt2, DisplayFunction -> $DisplayFunction], myInitialData, 
          Initialxsi, mydata, xsi}];
          
          myintegral[initdata_, initmiddata_, f1_, m_] := 
    Module[{data, midpts, endpts, initpts, data3, data4, myRect, myGraphics, 
        myLines, myPlot, g, res, intArea, areaRect, n1},
      data = initdata;
      midpts = initmiddata;
      endpts = Drop[data, 1];
      initpts = Drop[data, -1];
      data3 = Switch[m, 1, midpts, 2, endpts, 3, initpts, _, midpts];
      data4 = Partition[data, 2, 1];
      myRect = Map[Rectangle[{#[[1]], 0}, {#[[2]], g[c1]}] &, data4];
      areaRect = Map[(#[[2]]^2 - #[[1]]^2)g[c1] &, data4];
      res = areaRect Thread[c1 -> data3] /. g[c1] (c1 -> x_) -> g[x];
      intArea = π Apply[Plus, res] /. g[c1_] -> (f1 /. t -> c1);
      myGraphics = 
        Prepend[Map[Apply[ReplaceAll, #] &, myRect Thread[c1 -> data3]], 
          GrayLevel[0.7]];
      myLines = 
        Map[Line[{{#[[1]], 0}, {#[[2]], 0}, {#[[2]], g[c1]}, {#[[1]], 
                  g[c1]}, {#[[1]], 0}}] &, data4];
      myLineGraphics = 
        Prepend[Map[Apply[ReplaceAll, #] &, myLines Thread[c1 -> data3]], 
          GrayLevel[0]];
      myPlot = 
        Plot[f1, {t, First[initdata], Last[initdata]}, Axes -> True, 
          PlotStyle -> RGBColor[0, 0, 1], PlotRange -> All, 
          DisplayFunction -> Identity];
       
        Show[{Graphics[{myGraphics /. g[c1_] -> (f1 /. t -> c1), 
                myLineGraphics /. 
                  g[c1_] -> (f1 /. t -> c1), {RGBColor[1, 0, 0], 
                  PointSize[0.02], 
                  Map[Point[{#, 0}] &, data]}, {RGBColor[0, 0, 1], 
                  PointSize[0.015], Map[Point[{#, 0}] &, midpts]}}], myPlot}, 
          DisplayFunction -> $DisplayFunction, AspectRatio -> Automatic,PlotRange->All]];
          
    RiemannSum[f_, myPart_, int_, m_] := Module[{DeltaX, area, data3},
    data3 = 
      Switch[m, 1, myPart[[4 + int]], 2, Drop[myPart[[3 + int]], 1], 3, 
        Drop[myPart[[3 + int]], -1], _, myPart[[4 + int]]]; 
    DeltaX = Flatten[
        Partition[myPart[[3 + int]], 2, 1] /. {x_, y_} -> {y - x}];
    area = 
      Apply[Plus, Map[f1[#] &, data3]DeltaX] /. f1[x_] -> (f /. t -> x)];

Example 2:

Vapor Pressure module that uses a database with webMathematica (JLink version), (PHP version)

Programs for JLink example

vaporpressure. msp

<%Mathlet Get["SpeciesFunc.m"] %>
<html>

	<head>
		<meta name="generator" content="Adobe GoLive 4">
		<title>Vapor Pressure(MSP)</title>
	</head>

	<body bgcolor="white">
		<center>
			<h1>Pure Component Vapor Pressures<br>
			</h1>
		</center>
		<center>
		<p>Select a component from the box and then click on Submit to see the vapor pressure plot</p>
		<p>
	 
			<form name="FormName" action="vaporpressures" method="post">
			</p>
		<select name=speciesList>
		<option selected>Pick a species
		<%Mathlet MSPFunction[{},speciesOption[
			Module[ {my1, res},JavaBlock[
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my1 = LoadClass["Species1"];
				res=Species1`DBConnect[]]] ]]%>
		</select>
		<p></p>		
		<input type=submit name=submit value=submit>	
		</form>
		<input type="hidden" value="<%Mathlet $$mydata=paramList[$$speciesList]%>" name="somedata">
		<%Mathlet If[NumericQ[$$mydata[[1]]], " The Antoine paramaters for <b>"<>$$speciesList<>"</b> are:
		<table border=0 cellspacing=2 width=200>
		<tr>
			<td><center>A</center></td>
			<td><center>B</center></td>
			<td><center>C</center></td>
			</tr>
			<tr>
			<td>"<>ToString[$$mydata[[1]]]<>"</td>
			<td>"<>ToString[$$mydata[[2]]]<>"</td>
			<td>"<>ToString[$$mydata[[3]]]<>"</td></tr></table><br>
			where the Antoine Eqn is given by <br>"<>MSPFormat[HoldForm[P=Exp[A - B/(T+C)]],StandardForm]<>
			"<br> and the units are P (kPa) and T (K)",""]%>
			<%Mathlet If[NumericQ[$$mydata[[1]]],"<p> A plot of Antoine's Equation for <b>"<>$$speciesList<>"</b>
			 is shown below</p><p>",""]%>
			<%Mathlet If[NumericQ[$$mydata[[1]]],MSPShow[Plot[Exp[$$mydata[[1]] - $$mydata[[2]]/
			(T + 273.15 + $$mydata[[3]])],{T,0,200},PlotStyle -> RGBColor[0, 0, 1], Frame -> True, 
            FrameLabel -> {"T(C)", "P(kPa)"}]],""]%>
	
	</center>
	</body>
	</html>

speciesFunc. m

speciesOption[name_] := Module[{
      i = 1, myString = ""},
    While[i < Length[name]+1,
      myString = 
        StringJoin[myString, 
          "<option value=" <> ToString[name[[i]]] <> ">" <> 
            ToString[name[[i]]] <> "\n"]; i++]; myString]
paramList[mySelection_]:=JavaBlock[ 
		Module[ {my2, res2},
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my2 = LoadClass["SpeciesVP"];
				res2=SpeciesVP`DBConnect[ToString[mySelection]]
			] ];

Species1. java

import java.sql.*;
import java.util.*;


public class Species1 {

	public static String[] DBConnect() 
	{
		
		Vector dataRows =new Vector();
		String[] myData;
		
		try {
		Class.forName("org.gjt.mm.mysql.Driver").newInstance();
		}
		catch (Exception E){
			System.err.println("Unable to load driver");
			E.printStackTrace();
			}
		try{
			Connection C=DriverManager.getConnection(
			"jdbc:mysql://localhost/brian01?user=userID&password=mypassword");
			

		Statement stmt = C.createStatement();
		ResultSet rset = stmt.executeQuery("SELECT species_name from Antoineeqn
		 order by species_id;");
		
		int i=0;
		while(rset.next())	
		{		
			dataRows.addElement(rset.getString(1));
		}
		rset.close();
		stmt.close();
		C.close();
	  }
	catch (SQLException E){
	System.out.println("SQLException: " + E.getMessage());
	System.out.println("SQLState: " + E.getSQLState());
	System.out.println("VendorError: " + E.getErrorCode());
	}
	int j=dataRows.size();
	myData=new String[j];
	for(int i=0;i<j;i++)
	{

	myData[i]=(String)dataRows.elementAt(i);
	
	}
	return myData;

}
}

SpeciesVP. java

import java.sql.*;
import java.util.*;


public class SpeciesVP {

	public static Object DBConnect(String species) 
	{
		
		Vector dataRows =new Vector();
		float[] rowData;
		float[] myData;
	
		try {
		Class.forName("org.gjt.mm.mysql.Driver").newInstance();
		}
		catch (Exception E){
			System.err.println("Unable to load driver");
			E.printStackTrace();
			}
		try{
			Connection C=DriverManager.getConnection(
			"jdbc:mysql://localhost/brian01?user=userID&password=mypassword");
			
		PreparedStatement pstmt=C.prepareStatement("SELECT A,B,C from Antoineeqn
		 where species_name=?");
		pstmt.setString(1,species);
		ResultSet rset = pstmt.executeQuery();
			
		while(rset.next())
			
		{	
			rowData=new float[3];
			for(int i=0;i<3;i++){
				rowData[i]=rset.getFloat(i+1);
				}
				dataRows.addElement(rowData);
		
		
		}
	
		// Close result set, statement and DB connection
		//
		rset.close();
		//pstmt.close();
		C.close();
	  }
	catch (SQLException E){
	System.out.println("SQLException: " + E.getMessage());
	System.out.println("SQLState: " + E.getSQLState());
	System.out.println("VendorError: " + E.getErrorCode());
	}
	
	return  dataRows.elementAt(0);
}
}

Programs for PHP example

VaporPressure. php

<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
	<title>Vapor Pressure (PHP)</title>
	
	<script language="JavaScript">
	function myfunc(data){

	mySpecies=escape(data.speciesList.options[data.speciesList.selectedIndex].value);

	parent.plotFrame.document.location.href="../webMathematica/MSP/Examples/vapPressPlot.msp?speciesList="+mySpecies;
	}
	</script>
	
	<meta name="generator" content="BBEdit 6.0">
</head>
<body bgcolor="white">
		<center>
			<h1>Pure Component Vapor Pressures<br>
			</h1>
		</center>
		<center>
		<p>Select a component from the box and then click on Evaluate to see the vapor pressure plot</p>
		<p>
<form name="FormName" action="vaporpressures" method="post">
			</p>
		<select name=speciesList>
		<option selected>Pick a species
<?php
$connection=mysql_connect("localhost","userID","mypassword")
			or die ("Could not connect to server.");
		$db=mysql_select_db("Brian01",$connection)
			or die("Could not select database.");
		$sq1="SELECT species_name from Antoineeqn order by species_id";
		$result=mysql_query($sq1,$connection)
		or die ("can't perform Query1:create userfile");
		$mystring="";
		while($thedata=mysql_fetch_array($result)){
		$mystring=$mystring."<option value=".$thedata[0]. ">".$thedata[0]. "\n";}
		echo $mystring	
?>
</select>
<input type=button value=Evaluate onclick="myfunc(this.form)">
</form>
</center>

<table align=center border=0>
<tr><td><IFRAME src="../webMathematica/MSP/Examples/vapPressPlot.msp" align=center frameborder=0 width=400 height=500 name="plotFrame">
</IFRAME></td></tr>
</table>

</body>
</html>

VapPressPlot. msp

<%Mathlet Get["SpeciesFunc.m"] %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<script language="JavaScript">

</script>
	<title>Untitled</title>
</head>

<body>
<%Mathlet MSPBlock[{$$speciesList},$$mydata=paramList[$$speciesList]];%>
		<%Mathlet If[NumericQ[$$mydata[[1]]], " <Center>The Antoine paramaters for <b>"<>$$speciesList<>"</b> are:
		
		<table border=0 cellspacing=2 width=200>
		<tr>
			<td><center>A</center></td>
			<td><center>B</center></td>
			<td><center>C</center></td>
			</tr>
			<tr>
			<td>"<>ToString[$$mydata[[1]]]<>"</td>
			<td>"<>ToString[$$mydata[[2]]]<>"</td>
			<td>"<>ToString[$$mydata[[3]]]<>"</td></tr></table><br>
			where the Antoine Eqn is given by <br>"<>MSPFormat[HoldForm[P=Exp[A - B/(T+C)]],StandardForm]<>
			"<br> and the units are P (kPa) and T (K)" ,""]%>
			
			<%Mathlet If[NumericQ[$$mydata[[1]]],"<p> A plot of Antoine's Equation for <b>"<>$$speciesList<>"</b>
			is shown below</p><p>",""]%>
			<%Mathlet If[NumericQ[$$mydata[[1]]],
			MSPShow[Plot[Exp[$$mydata[[1]] - $$mydata[[2]]/(T + 273.15 + $$mydata[[3]])],{T,0,200},
			PlotStyle -> RGBColor[0, 0, 1], Frame -> True, 
  			FrameLabel -> {"T(C)", "P(kPa)"}]],""]%>
  			
</center>
</body>
</body>
</html>

Example 3:

Background on Isothermal Flash Calculation (link)

Isothermal Flash Calculation (link)

Programs for Isothermal Flash example

Kvalues.msp

<%Mathlet Get["SpeciesFunc.m"] %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
	<title>Flash Unit Results</title>
	<Script Language=JAVASCRIPT>
	function submitData2(myDataForm){
	if(validInput1(myDataForm.T.value)=="A"){
	alert("You must enter a value for T >0")
	myDataForm.T.focus()
	myDataForm.T.select()
	return false
	}
	else if(validInput1(myDataForm.T.value)=="B"){
	alert("The value you entered for T has an illegal character ")
	myDataForm.T.focus()
	myDataForm.T.select()
	return false
	}
	if(validInput1(myDataForm.P1.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	else if(validInput1(myDataForm.P1.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	if(validInput1(myDataForm.P2.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P2.focus()
	myDataForm.P2.select()
	return false
	}
	else if(validInput1(myDataForm.P2.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P2.focus()
	myDataForm.P2.select()
	return false
	}
	
	else{
	return true
	}
	}
	
	function validInput1(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	if(myinput1<0){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	
	return "T"
	}
	</script>
	<meta name="generator" content="BBEdit 6.0">
</head>

	<body bgcolor="white">
	
		
		<%Mathlet MSPBlock[{$$mylist,$$T,$$P2},
		"<center><h4>Results for Flash Unit</h4></center>
		<br>
		<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr><th colspan=2 bgcolor=yellow align=center>Flash Unit K-values</th></tr><tr>
		<th><font size=2> Species</font></th><th><font size=2>K-Value</font></th>
		</tr>"
		
		<>Module[{
      i = 1, myString = ""},
    While[i < Length[ToExpression[$$mylist]]+1,
      myString = 
        StringJoin[myString, 
          "<tr><td><font size=2>"<> ToString[ToExpression[$$mylist][[i]]] <> "</font></td><td><font size=2>"<>
          ToString[KValues[ToExpression[$$mylist],$$T,$$P2,paramList][[i]]]<>"</font>
          </td></tr>"]; i++]; myString]]%>
		</table>

		
		<%Mathlet MSPBlock[{$$mylist},tableTitles=Join[ToExpression[$$mylist],
		{"Flow Rate (mol/hr)","Temperature (C)","Pressure (kPa)"}];]%>
		<p>
		<%Mathlet MSPBlock[{$$mylist,$$xilist,$$T,$$P1,$$P2,$$F},myresults=IsoThermalFlash[KValues[ToExpression[$$mylist],$$T,$$P2,paramList],
		 ToExpression[$$xilist], $$T, $$P1,$$P2, $$F];]%>

		 
		 <p><%Mathlet MSPBlock[{$$mylist},nspecies=Length[ToExpression[$$mylist]]+1;]%>
		 <%Mathlet If[Length[myresults]>0,
		 "<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr>
		<th Colspan=4 align=center bgcolor=yellow>Flash Unit Specifications</th></tr><tr>
		<th><font size=2> Variable</font></th><th><font size=2>Feed Stream</font></th>
		<th><font size=2>Vapor Stream</font></th><th><font size=2>Liquid Stream</font></th>
		</tr>
		<tr>
		<td>"
		<>Module[{
      i = 1, myString = ""},
    While[i < Length[ToExpression[myresults[[1]]]]+1,
      myString = 
        StringJoin[myString, 
          "<tr><td align=center><font size=2>"<>If[i<nspecies,ToString[tableTitles[[i]]]<>" (mol frac)",ToString[tableTitles[[i]]]]<>"</font></td>
          <td align=center><font size=2>"<> ToString[myresults[[1,i]]] <>
           "</font></td><td align=center><font size=2>"<>
          ToString[myresults[[2,i]]] <>"</font></td><td align=center><font size=2>"<>
          ToString[myresults[[3,i]]]<>"</font>
          </td></tr>"]; i++]; StringJoin[myString,
          "</table><form onSubmit='return submitData2(this)' name=Form3 action='Kvalues' method='post'>
          <center><font size=2 ><P>
          
         <b> Use the following form to enter new exit Temperature/Pressure values.</b></p></font></center>
          <table align=center><tr><td><font size =2>Temperature (C)</font></td><td><input type=text name=T size=8 value='' ></td>
		<td><font size =2>Pressure (kPa)</font></td><td><input type=text name=P2 size=8 value='' ></td>
		</tr></table>
		<input type=hidden name=mylist value='"<>ToString[ToExpression[$$mylist]]<>"'>
		<input type=hidden name=xilist value='"<>ToString[ToExpression[$$xilist]]<>"'>
		<input type=hidden name=P1 value='"<>ToString[$$P1]<>"'>
		<input type=hidden name=F value='"<>ToString[$$F]<>"' >
		<p><center><input type=submit value='Submit Data' name=submit2></center></form>"]],
		
		"<form onSubmit='return submitData2(this)' name=Form3 action='Kvalues' method='post'>
          <center><font size=2 color=red><b>For the Temperature/Pressure values (T="<>ToString[$$T]<>" C,P="<>
          ToString[$$P2]<>" kPa) selected there is no solution.</b></font><P>
          
          <font size=2>Use the following form to enter new values.</font></p></center>
          <table align=center><tr><td><font size =2>Temperature (C)</font></td><td><input type=text name=T size=8 value='' ></td>
		<td><font size =2>Pressure (kPa)</font></td><td><input type=text name=P2 size=8 value='' ></td>
		</tr></table>
		<input type=hidden name=mylist value='"<>ToString[ToExpression[$$mylist]]<>"'>
		<input type=hidden name=xilist value='"<>ToString[ToExpression[$$xilist]]<>"'>
		<input type=hidden name=P1 value='"<>ToString[$$P1]<>"'>
		<input type=hidden name=F value='"<>ToString[$$F]<>"' >
		<p><center><input type=submit value='Submit Data' name=submit2></center></form>"]%>
	
		

	<center>
<p><input type="button" value="New Calculation" onclick=parent.FeedSpecies.document.location.href="SelectSpecies.msp"></center>	
		
		


</html>

SelectSpecies.msp

<%Mathlet Get["SpeciesFunc.m"] %>
<html>

	<head>
		<meta name="generator" content="Adobe GoLive 4">
		<title>Select Species</title>
		<Script Language=JAVASCRIPT>
	function submitData(myDataForm){
	if(validInput(myDataForm.xi.value)=="A"){
	alert("You must enter a value for xi >0")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="B"){
	alert("The value you entered has an illegal character ")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="C"){
	alert("The value of xi must be <=1 ")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="D"){
	alert("The sum of all xi is "+sumxi)
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else{
	return true
	}
	}
	
	function submitData2(myDataForm){
	if(validInput1(myDataForm.T.value)=="A"){
	alert("You must enter a value for T >0")
	myDataForm.T.focus()
	myDataForm.T.select()
	return false
	}
	else if(validInput1(myDataForm.T.value)=="B"){
	alert("The value you entered for T has an illegal character ")
	myDataForm.T.focus()
	myDataForm.T.select()
	return false
	}
	if(validInput1(myDataForm.P1.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	else if(validInput1(myDataForm.P1.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	if(validInput1(myDataForm.P2.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P2.focus()
	myDataForm.P2.select()
	return false
	}
	else if(validInput1(myDataForm.P2.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P2.focus()
	myDataForm.P2.select()
	return false
	}
	else if(validInput1(myDataForm.F.value)=="B"){
	alert("The value you entered for F has an illegal character ")
	myDataForm.F.focus()
	myDataForm.F.select()
	return false
	}
	if(validInput1(myDataForm.F.value)=="A"){
	alert("You must enter a value for F >0")
	myDataForm.F.focus()
	myDataForm.F.select()
	return false
	}
	else{
	return true
	}
	}
	
	function validInput(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		<%Mathlet MSPBlock[{$$n,$$xi,$$xilist},If[$$n===Null, xilist1={};AppendTo[xilist1,ToString[$$xi]];prevxi=ToString[Apply[Plus,ToExpression[xilist1]]];
	"sumxi=parseFloat(myinput1)+parseFloat("<>prevxi<>")"
	,xilist1=AppendTo[ToExpression[$$xilist], ToString[$$xi]];prevxi=ToString[Apply[Plus,ToExpression[xilist1]]];
		"sumxi=parseFloat(myinput1)+parseFloat("<>prevxi<>")"]]%>
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	if(myinput1>1){
	return "C"
	}
	if(sumxi>1){
	return "D"
	}
	
	
	return "F"
	}
	
	function validInput1(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	if(myinput1<0){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	
	return "T"
	}
	
	</Script>
	<Script Language=JAVASCRIPT>
	 function myfunc(data){
	
	 parent.KValues.document.location.href='KValues.msp?n='+escape(data.n.value)+'&xilist='+escape(data.xilist.value)+'&mylist='+escape(data.mylist.value);
	 }
	 
	 function sideBar2Window(data){
		var sidepage=data;
		sideBar2Window7_4_2=window.open(sidepage,'mywindow4','width=600,height=500,toolbar=no,scrollbars=yes,menubar=no,left=100,top=0');
		}
	
	</Script>
	
	</head>

	<body bgcolor="white">
	
			<center><h4>Flash Unit Feed Compositions and Operating Parameters<br>
			</h4>
		
				
		<font size=2>Use the form below to add components and their compositions to the feed stream.<br>
		 For background information on flash calculations, click, <A href="javascript:sideBar2Window('../../../WRIDevConf/IsoThermalFlash.html')">  here<a>
	
		
	  <%Mathlet MSPBlock[{$$n},If[$$n===Null,n=ToString[1],n=ToString[$$n+1]];""]%>
	  <%Mathlet MSPBlock[{$$n,$$speciesList,$$mylist},If[$$n===Null, mylist={};AppendTo[mylist,ToString[$$speciesList]];"",mylist=AppendTo[ToExpression[$$mylist], ToString[$$speciesList]];""]]%>
		  <%Mathlet MSPBlock[{$$n,$$xi,$$xilist},If[$$n===Null, xilist={};AppendTo[xilist,ToString[$$xi]];"",xilist=AppendTo[ToExpression[$$xilist], ToString[$$xi]];""]]%>
	
			<form onSubmit="return submitData(this)" name="FormName" action="SelectSpecies" method="post">
		<table align=center>
		<tr>
		
		<td><select name=speciesList>
	
		<%Mathlet MSPFunction[{},speciesOption[

		
			Module[ {my1, res},JavaBlock[
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my1 = LoadClass["Species1"];
				res=Species1`DBConnect[]]
			] ]]%>
		
		
		</select></td>
		<p></p>
		<input type=hidden name=n value="<%Mathlet MSPBlock[{$$n},ToString[n]] %>">
		<input type=hidden name=mylist value="<%Mathlet MSPBlock[{$$mylist},ToString[mylist]] %>">
		<input type=hidden name=xilist value="<%Mathlet MSPBlock[{$$xilist},ToString[xilist]] %>">
		
		
		
		
		
		<td><font size=2>mole fraction</font></td>
		<td><input type="text" name="xi" size="4" value="0" ></td>
		<td><input type=submit name=submit value='Add to Feed Stream'>
		</td>
		</tr>
		</table>
		<p>
		<%Mathlet MSPBlock[{$$n},
		"The species and compositions you have selected for the feed stream are shown below:
		<P>
		<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr>
		<th bgcolor=yellow><font size=2> Species</font></th><th bgcolor=yellow><font size=2>x<sub>i</sub></font></th>
		</tr>"
		<>Module[{
      i = 1, myString = ""},
    While[i < Length[mylist]+1,
      myString = 
        StringJoin[myString, 
          "<tr><td><font size=2>"<> ToString[mylist[[i]]] <> "</font></td><td><font size=2>"<>
          ToString[xilist[[i]]]<>"</font></td></tr>"]; i++]; myString]<>"
         <tr><td><font size=2><b>Total x<sub>i</sub></b></font></td><td><font size=2>"<>ToString[Apply[Plus,ToExpression[xilist]]]<>"</font>"]%></b>
            	</td>
            	</tr>
            	</table>
	<%Mathlet MSPBlock[{$$n},If[Apply[Plus,ToExpression[xilist]]<1,"<p>If you made an error, click on the Re-enter Data button.<br>
		
		<table align=center><tr><td><input type=button value=Re-enter Data onClick=window.location='SelectSpecies.msp'></td></tr></table>","",""]]%>
		</form>
		

		
		<%Mathlet If[Apply[Plus,ToExpression[xilist]]==1,"<form onSubmit='return submitData2(this)' name=Form2 action='Kvalues' method='post'> <p><font size =2>
		 Now use the following form to enter the 
		inlet and exit pressures (<b>P</b>), inlet temperature (<b>T</b>) and molar feed rate (<b>F</b>)
		<p>
		<table align=center><tr><td><font size =2>Inlet Temperature (C)</font></td><td><input type=text name=T size=8 value='' ></td>
		<td><font size =2>Inlet Pressure (kPa)</font></td><td><input type=text name=P1 size=8 value='' ></td>
		</tr><tr><td><font size =2>Exit Pressure (kPa)</font></td><td><input type=text name=P2 size=8 value='' ></td>
		<td><font size =2>Inlet Feed rate (mole/hr)</font></td><td><input type=text name=F size=8 value='' ></td></tr></table>
		<input type=hidden name=mylist value='"<>ToString[ToExpression[mylist]]<>"'>
		<input type=hidden name=xilist value='"<>ToString[ToExpression[xilist]]<>"'>
		<p><input type=submit value='Submit Data' name=submit2></form>
		","",""]%>
		
		
		
            	
            	
		
			</div>
			
	
		</center>
		</body>

</html>

speciesFunc. m

speciesOption[name_] := Module[{
      i = 1, myString = ""},
    While[i < Length[name]+1,
      myString = 
        StringJoin[myString, 
          "<option value=" <> ToString[name[[i]]] <> ">" <> 
            ToString[name[[i]]] <> "\n"]; i++]; myString]
paramList[mySelection_]:=JavaBlock[ 
		Module[ {my2, res2},
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my2 = LoadClass["SpeciesVP"];
				res2=SpeciesVP`DBConnect[ToString[mySelection]]
			] ];
			
KValues[species_,temp_,pres_,paramList_]:=Module[{mydata,parP,Kvalues},
mydata=Map[paramList[#]&,species];
		parP=Map[Exp[#[[1]] - #[[2]]/(temp + 273.15 + #[[3]])]&,mydata];
		Kvalues=Map[#/pres&,parP]];
		
IsoThermalFlash[kval_, initMolFrac_, initT_, inletP_,exitP_, initF_] := 
  Module[{K, x, F, T, P, moleFracEqns, speciesEqns, equilEqns1, equilEqns2, 
      strVarEqns, systemEqns, sol, res, n},
    n = Length[kval];
    K[i_] := kval[[i]];
    moleFracEqns = Table[Sum[x[i, m], {i, 1, n}] == 1, {m, 1, 3}];
    speciesEqns = 
      Table[x[i, 1]F[1] == x[i, 2]F[2] + x[i, 3] F[3], {i, 1, n}];
    
    equilEqns1 = {T[2] == T[3], P[2] == P[3],  T[1] == T[2]};
    equilEqns2 = Table[x[i, 2] == K[i] x[i, 3], {i, 1, n}];
    strVarEqns = 
      Drop[Join[
          Table[x[i, 1] == initMolFrac[[i]], {i, 1, n}], {T[1] == initT, 
            P[1] == inletP, P[2]==exitP, F[1] == initF}], 1];
    systemEqns = 
      Join[speciesEqns, moleFracEqns, equilEqns1, equilEqns2, strVarEqns];
    sol = Solve[systemEqns];
    res = {Join[Table[x[i, 1], {i, 1, n}], {F[1], T[1], P[1]}], 
          Join[Table[x[i, 2], {i, 1, n}], {F[2], T[2], P[2]}], 
          Join[Table[x[i, 3], {i, 1, n}], {F[3], T[3], P[3]}]} /. sol;
    Flatten[DeleteCases[
        Map[If[Length[Select[Flatten[#], # < 0 &]] > 0, -1, #] &, res], 
        x_ /; x < 0, Infinity], 1]];

Example 4:

Background on batch distillation (link)

Batch Distillation (link)

Programs for Batch Distillation example

BatchDistCalc.m

batchDist[A_, B_, P_, x1_, x2_,L0_,species_] := 
  Module[{eqn1, L, k2, k1, T, x, eqn2, eqn3, T1, eqn4}, 
    eqn1 = {L'[x] == L[x]/(x(k1[T[x]] - 1)), L[x1] == L0};
k1[T_] := Exp[A[[1]] - A[[2]]/(T + 273.15 + A[[3]])]/P;
k2[T_] := Exp[B[[1]] - B[[2]]/(T + 273.15 + B[[3]])]/P;
eqn2 = D[(x k1[T[x]] + (1 - x) k2[T[x]] == 0), x];
eqn3 = Join[First[Solve[eqn2, T'[x]]] /. Rule -> Equal, {T[x1] == T1}];
T1 = T /. FindRoot[x1 k1[T] + (1 - x1) k2[T] == 1, {T, 0}];
eqn4 = Join[eqn1, eqn3];
sol = NDSolve [eqn4, {L[x], T[x]}, {x, x1, x2}];
plt1 = Plot[Evaluate[{L[x], T[x]} /. sol], {x, x1, x2}, 
        PlotStyle -> {RGBColor[0, 0, 1], RGBColor[1, 0, 0]}, Frame -> True, 
        FrameLabel -> {StyleForm[ToString[species]<>",x",FontSize->12],
         "\!\(\*
StyleBox[\"L\",\nFontColor->RGBColor[0, 0, 1],FontSize->12]\),\!\(\*
StyleBox[\"T\",\nFontColor->RGBColor[1, 0, 0],FontSize->12]\)"}, 
        DisplayFunction -> Identity];
res = {Show[plt1, DisplayFunction -> $DisplayFunction],
T1, First[T[x] /. sol /. x -> x2], L0,
        First[L[x] /. sol /. x -> x2],
x1,x2}]

Batchspecies.msp

<%Mathlet Get["SpeciesFunc.m"] %>
<html>

	<head>
		<meta name="generator" content="Adobe GoLive 4">
		<title>Batch Distillation</title>
		<Script Language=JAVASCRIPT>
	function submitData(myDataForm){
	if((myDataForm.n.value)>1){
	alert("You cannot enter more than two species. Re-enter data")
	myDataForm.ReEnter.focus()
	
	return false
	}
	
	else if(validInput(myDataForm.xi.value)=="A"){
	alert("You must enter a value for xi >0")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="B"){
	alert("The value you entered has an illegal character ")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="C"){
	alert("The value of xi must be <=1 ")
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else if(validInput(myDataForm.xi.value)=="D"){
	alert("The sum of all xi is "+sumxi)
	myDataForm.xi.focus()
	myDataForm.xi.select()
	return false
	}
	else{
	return true
	}
	}
	
	function submitData2(myDataForm){
	if(validInput1(myDataForm.L.value)=="A"){
	alert("You must enter a value for L >0")
	myDataForm.L.focus()
	myDataForm.L.select()
	return false
	}
	else if(validInput1(myDataForm.L.value)=="B"){
	alert("The value you entered for L has an illegal character ")
	myDataForm.L.focus()
	myDataForm.L.select()
	return false
	}
	if(validInput1(myDataForm.P1.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	else if(validInput1(myDataForm.P1.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	if(validInput1(myDataForm.xf.value)=="A"){
	alert("You must enter a value for xf >0")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	else if(validInput1(myDataForm.xf.value)=="B"){
	alert("The value you entered for xf has an illegal character ")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	else if(validInput2(myDataForm.xf.value)=="C"){
	alert("The value of xf must be <=1 ")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	else{
	return true
	}
	}
	
	function validInput(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		<%Mathlet MSPBlock[{$$n,$$xi,$$xilist},If[$$n===Null, xilist1={};AppendTo[xilist1,ToString[$$xi]];prevxi=ToString[Apply[Plus,ToExpression[xilist1]]];
	"sumxi=parseFloat(myinput1)+parseFloat("<>prevxi<>")"
	,xilist1=AppendTo[ToExpression[$$xilist], ToString[$$xi]];prevxi=ToString[Apply[Plus,ToExpression[xilist1]]];
		"sumxi=parseFloat(myinput1)+parseFloat("<>prevxi<>")"]]%>
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	if(myinput1>1){
	return "C"
	}
	if(sumxi>1){
	return "D"
	}
	
	
	return "F"
	}
	
	function validInput1(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	if(myinput1<0){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	
	return "T"
	}
	function validInput2(myinput1){
	if(myinput1>1){
	return "C"
	}
	return "T"
	}
	
	</Script>
	<Script Language=JAVASCRIPT>
	 function myfunc(data){
	
	 parent.KValues.document.location.href='KValues.msp?n='+escape(data.n.value)+'&xilist='+escape(data.xilist.value)+'&mylist='+escape(data.mylist.value);
	 }
	 
	 function sideBar2Window(data){
		var sidepage=data;
		sideBar2Window7_4_2=window.open(sidepage,'mywindow4','width=600,height=500,toolbar=no,scrollbars=yes,menubar=no,left=100,top=0');
		}
	</Script>
	
	</head>

	<body bgcolor="white">
	
			<center><h4>Binary Batch Distillation Compositions and Operating Parameters<br>
			</h4>
		
		
	<font size=2>Use the form below to add two components and their initial compositions to the batch still.<br>For background information on batch distillation, click, <A href="javascript:sideBar2Window('../../../WRIDevConf/BatchDist.html')">  here<a>
	
		
	  <%Mathlet MSPBlock[{$$n},If[$$n===Null,n=ToString[1],n=ToString[$$n+1]];""]%>
	  <%Mathlet MSPBlock[{$$n,$$speciesList,$$mylist},
	  If[$$n===Null,  mylist={};AppendTo[mylist,ToString[$$speciesList]];"",
	  mylist=AppendTo[ToExpression[$$mylist], ToString[$$speciesList]];""]]%>
	<%Mathlet MSPBlock[{$$n,$$xi,$$xilist},If[$$n===Null,
	xilist={}; AppendTo[xilist,ToString[$$xi]];"",
	xilist=AppendTo[ToExpression[$$xilist], ToString[$$xi]];""]]%>
	
	<form onSubmit="return submitData(this)" name="FormName" 
	action="BatchSpecies" method="post">
		<table align=center>
		<tr>
		
		<td><select name=speciesList>
	
		<%Mathlet MSPFunction[{},speciesOption[
			Module[ {my1, res},JavaBlock[
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my1 = LoadClass["Species1"];
				res=Species1`DBConnect[]]
			] ]]%>
			
		</select></td>
		<p></p>
		<input type=hidden name=n value="<%Mathlet MSPBlock[{$$n},ToString[n]] %>">
		<input type=hidden name=mylist value="<%Mathlet MSPBlock[{$$mylist},
		ToString[mylist]] %>">
		<input type=hidden name=xilist value="<%Mathlet MSPBlock[{$$xilist},
		ToString[xilist]] %>">
		<td><font size=2>mole fraction</font></td>
		<td><input type="text" name="xi" size="4" value="0" ></td>
		<td><input type=submit name=submit value='Add to Batch Still'>
		</td>
		</tr>
		</table>
		<p>
		<%Mathlet MSPBlock[{$$n},
		"The species and compositions you have selected for the batch still are shown below:
		<P>
		<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr>
		<th bgcolor=yellow><font size=2> Species</font></th><th bgcolor=yellow>
		<font size=2>x<sub>i</sub></font></th>
		</tr>"
		<>Module[{
      i = 1, myString = ""},
    While[i < Length[mylist]+1,
      myString = 
        StringJoin[myString, 
          "<tr><td><font size=2>"<> ToString[mylist[[i]]] <> "</font></td><td><font size=2>"<>
          ToString[xilist[[i]]]<>"</font></td></tr>"]; i++]; myString]<>"
         <tr><td><font size=2><b>Total x<sub>i</sub></b></font></td><td>
         <font size=2>"<>ToString[Apply[Plus,ToExpression[xilist]]]<>"</font>"]%></b>
            	</td>
            	</tr>
            	</table>
	<%Mathlet MSPBlock[{$$n},If[Apply[Plus,ToExpression[xilist]]<1,"<p>If you made
	 an error, click on the Re-enter Data button.<br>
		
		<table align=center><tr><td><input type=button value='Re-enter Data' 
		name=ReEnter onClick=window.location='BatchSpecies.msp'></td></tr></table>","",""]]%>
		</form>
		
		<%Mathlet MSPBlock[{$$n},If[Apply[Plus,ToExpression[xilist]]==1,
		"<center><font size=2>The K-values for the species you selected are shown
		 below at STP conditions.</font></center>
		<br>
		<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr><th colspan=2 bgcolor=yellow align=center>K-values at STP</th></tr><tr>
		<th><font size=2> Species</font></th><th><font size=2>K-Value</font></th>
		</tr>"
		<>Module[{
      i = 1, myString = ""},
    While[i < Length[ToExpression[mylist]]+1,
      myString = 
        StringJoin[myString, 
          "<tr><td><font size=2>"<> ToString[ToExpression[mylist][[i]]]
          <> "</font></td><td><font size=2>"<>
          ToString[KValues[ToExpression[mylist],25,101.5,paramList][[i]]]<>"</font>
          </td></tr>"]; i++]; myString]],""]%>
		</table>

	<%Mathlet myKValues=KValues[ToExpression[mylist],25,101.5,paramList];%>
		
		<%Mathlet If[Apply[Plus,ToExpression[xilist]]==1,"<form 
		onSubmit='return submitData2(this)' name=Form2 
		action='batchDistResults' method='post'> <p><font size =2>
		 Now use the following form to enter the operating pressure (<b>P</b>)
		  for the still, <br>the initial liquid charge (<b>F</b>), and the final
		   composition of<b> "<>ToString[mylist[[1]]]<>"</b> in the still.<br> Note: since 
		<b>"<>ToString[mylist[[1]]]<>"</b> is the "<>If[myKValues[[1]]>
		myKValues[[2]]," more"," less"]<> " volatile species, its final composition
		 must be"<>If[myKValues[[1]]>myKValues[[2]],"less than ","greater
		  than "]<>"<b>"<>ToString[xilist[[1]]]<>"</b>.
		<p>
		<table align=center><tr><td align=center><font size =2>Initial liquid
		 charge (mol)</font></td><td><input type=text name=L size=8 value='' ></td>
		<td align=center><font size =2>Operating Pressure (kPa)</font></td><td>
		<input type=text name=P1 size=8 value='' ></td>
		</tr><tr>
		<td align=center><font size =2>Final composition of " <>ToString[mylist[[1]]]
		<>" (mole frac)</font></td><td><input type=text name=xf size=8
		 value='' ></td></tr></table>
		<input type=hidden name=mylist value='"<>ToString[ToExpression[mylist]]<>"'>
		<input type=hidden name=xilist value='"<>ToString[ToExpression[xilist]]<>"'>
		<input type=hidden name=x0 value='"<>ToString[ToExpression[xilist][[1]]]<>"'>
		<p><input type=submit value='Submit Data' name=submit2></form>
		","",""]%>
		
		</center>
		</body>

</html>

BatchDistResults.msp

<%Mathlet Get["SpeciesFunc.m"] %>
<%Mathlet Get["batchDistCalc.m"] %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
	<title>Flash Unit Results</title>
	<Script Language=JAVASCRIPT>
	function submitData2(myDataForm){
	if(validInput1(myDataForm.L.value)=="A"){
	alert("You must enter a value for L >0")
	myDataForm.L.focus()
	myDataForm.L.select()
	return false
	}
	else if(validInput1(myDataForm.L.value)=="B"){
	alert("The value you entered for L has an illegal character ")
	myDataForm.L.focus()
	myDataForm.L.select()
	return false
	}
	if(validInput1(myDataForm.P1.value)=="A"){
	alert("You must enter a value for P >0")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	else if(validInput1(myDataForm.P1.value)=="B"){
	alert("The value you entered for P has an illegal character ")
	myDataForm.P1.focus()
	myDataForm.P1.select()
	return false
	}
	if(validInput1(myDataForm.xf.value)=="A"){
	alert("You must enter a value for xf >0")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	else if(validInput1(myDataForm.xf.value)=="B"){
	alert("The value you entered for xf has an illegal character ")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	else if(validInput(myDataForm.xf.value)=="C"){
	alert("The value of xf must be <=1 ")
	myDataForm.xf.focus()
	myDataForm.xf.select()
	return false
	}
	
	else{
	return true
	}
	}
	
	function validInput1(myinput1){
		invalidChars="-~!@#$%^&*,<>?"
		
		
	if(myinput1==0){
	return "A"
	}
	if(myinput1=="0"){
	return "A"
	}
	if(myinput1<0){
	return "A"
	}
	
	for(i=0;i<invalidChars.length;i++){
	badChar=invalidChars.charAt(i)
	if(myinput1.indexOf(badChar)> -1){
	return "B"
	}
	}
	
	return "T"
	}
	function validInput(myinput1){
	if(myinput1>1){
	return "C"
	}
	return "T"
	}
	</script>
	<meta name="generator" content="BBEdit 6.0">
</head>

	<body bgcolor="white">
	<center><h4>Results for Binary Batch Distillation</h4></center>
		<br>
		<%Mathlet MSPBlock[{$$mylist},myKValues=KValues[ToExpression[$$mylist],25,101.5,paramList]];%>
		<%Mathlet MSPBlock[{$$mylist},myParam=Map[paramList[#]&,$$mylist]];%>
	  <%Mathlet MSPBlock[{$$L,$$P1,$$x0,$$xf,$$mylist},myresults=Take[batchDist[myParam[[1]],
	  myParam[[2]], $$P1, $$x0, $$xf,$$L,$$mylist[[1]]],{2,7}]];%>
	
	 <%Mathlet 
		 "<table align=center border=1 cellspacing=0 cellpadding=5>
		<tr>
		<th Colspan=4 align=center bgcolor=yellow>Batch Distillation Results</th></tr><tr>
		<th><font size=2> Variable</font></th><th><font size=2>Initial Value</font></th>
		<th><font size=2>Final Value</font></th>
		</tr>
		<tr>
		<td align=center><font size=2>Bubble Temperature,T (C)</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[1]]]<>"</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[2]]]<>"</font></td>
		</tr><tr>
		<td align=center><font size=2>Liquid Charge, L (moles)</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[3]]]<>"</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[4]]]<>"</font></td>
		</tr><tr>
		<td align=center><font size=2>"<>ToString[ToExpression[$$mylist][[1]]]<> ", x (mole frac)</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[5]]]<>"</font></td>
		<td align=center><font size=2>"<>ToString[myresults[[6]]]<>"</font></td>
		</tr>
		</table>"%>
		
<center><p></p><p></p><font size=2> A graphical representation of the results for the batch distillation is shown below:
<p></p><p></p>
		<%Mathlet MSPBlock[{$$L,$$P1,$$x0,$$xf,$$mylist},MSPShow[batchDist[myParam[[1]],
	  myParam[[2]], $$P1, $$x0, $$xf,$$L,$$mylist[[1]]][[1]]]]%>

<p>

          <center><font size=2 ><P>
          
         <%Mathlet MSPBlock[{$$mylist,$$xilist},"<form onSubmit='return submitData2(this)' name=Form2 action='batchDistResults' method='post'> <p><font size =2>
		 Use the following form to enter new operating values for the still: 
		operating pressure (<b>P</b>), <br>the initial liquid charge (<b>F</b>), and  final composition of<b> "<>ToString[$$mylist[[1]]]<>"</b> in the still.<br> Note: since 
		<b>"<>ToString[$$mylist[[1]]]<>"</b> is the "<>If[myKValues[[1]]>myKValues[[2]]," more"," less"]<> " volatile species, its final composition must be
		"<>If[myKValues[[1]]>myKValues[[2]],"less than ","greater than "]<>"<b>"<>ToString[$$xilist[[1]]]<>"</b>.
		<p>
		<table align=center><tr><td align=center><font size =2>Initial liquid charge (mol)</font></td><td><input type=text name=L size=8 value='' ></td>
		<td align=center><font size =2>Operating Pressure (kPa)</font></td><td><input type=text name=P1 size=8 value='' ></td>
		</tr><tr>
		<td align=center><font size =2>Final composition of " <>ToString[$$mylist[[1]]]<>" (mole frac)</font></td><td><input type=text name=xf size=8 value='' ></td></tr></table>
		<input type=hidden name=mylist value='"<>ToString[ToExpression[$$mylist]]<>"'>
		<input type=hidden name=xilist value='"<>ToString[ToExpression[$$xilist]]<>"'>
		<input type=hidden name=x0 value='"<>ToString[ToExpression[$$xilist][[1]]]<>"'>
		<p><input type=submit value='Submit Data' name=submit2></form>"
		]%>
	 
	 						
		

		
		<center>
<p><input type="button" value="New Calculation" onclick=parent.FeedSpecies.document.location.href="BatchSpecies.msp"></center>	
		
		

</body>
</html>

Example 5:

Background on non-ideal solutions (link)

Phase behavior of non-ideal binary mixtures (link)

Programs for Non-Ideal Solutions example

speciesFunc.m

speciesOption[name_] := Module[{
      i = 1, myString = ""},
    While[i < Length[name]+1,
      myString = 
        StringJoin[myString, 
          "<option value=" <> ToString[name[[i]]] <> ">" <> 
            ToString[name[[i]]] <> "\n"]; i++]; myString]
paramList[mySelection_]:=JavaBlock[ 
		Module[ {my2, res2},
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my2 = LoadClass["SpeciesVP"];
				res2=SpeciesVP`DBConnect[ToString[mySelection]]
			] ];
binarySpeciesList[mySelection_]:=JavaBlock[ 
		Module[ {my2, res2},
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my2 = LoadClass["vanLaarParam1"];
				res2=vanLaarParam1`DBConnect2[mySelection]
			] ];
BinaryParamList[mySelection_]:=JavaBlock[ 
		Module[ {my2, res2},
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my2 = LoadClass["vanLaarParam1"];
				res2=vanLaarParam1`DBConnect[ToString[mySelection]]
			] ];
			
KValues[species_,temp_,pres_,paramList_]:=Module[{mydata,parP,Kvalues},mydata=Map[paramList[#]&,species];
		parP=Map[Exp[#[[1]] - #[[2]]/(temp + 273.15 + #[[3]])]&,mydata];
		Kvalues=Map[#/pres&,parP]];
		
IsoThermalFlash[kval_, initMolFrac_, initT_, inletP_,exitP_, initF_] := 
  Module[{K, x, F, T, P, moleFracEqns, speciesEqns, equilEqns1, equilEqns2, 
      strVarEqns, systemEqns, sol, res, n},
    n = Length[kval];
    K[i_] := kval[[i]];
    moleFracEqns = Table[Sum[x[i, m], {i, 1, n}] == 1, {m, 1, 3}];
    speciesEqns = 
      Table[x[i, 1]F[1] == x[i, 2]F[2] + x[i, 3] F[3], {i, 1, n}];
    
    equilEqns1 = {T[2] == T[3], P[2] == P[3],  T[1] == T[2]};
    equilEqns2 = Table[x[i, 2] == K[i] x[i, 3], {i, 1, n}];
    strVarEqns = 
      Drop[Join[
          Table[x[i, 1] == initMolFrac[[i]], {i, 1, n}], {T[1] == initT, 
            P[1] == inletP, P[2]==exitP, F[1] == initF}], 1];
    systemEqns = 
      Join[speciesEqns, moleFracEqns, equilEqns1, equilEqns2, strVarEqns];
    sol = Solve[systemEqns];
    res = {Join[Table[x[i, 1], {i, 1, n}], {F[1], T[1], P[1]}], 
          Join[Table[x[i, 2], {i, 1, n}], {F[2], T[2], P[2]}], 
          Join[Table[x[i, 3], {i, 1, n}], {F[3], T[3], P[3]}]} /. sol;
    Flatten[DeleteCases[
        Map[If[Length[Select[Flatten[#], # < 0 &]] > 0, -1, #] &, res], 
        x_ /; x < 0, Infinity], 1]];
        
     BPPress[P1_, P2_, A_, B_] := 
  Module[{gam1, gam2, x, y1, plt1, PB}, 
    gam1[x_] := Exp[A/((1 + A x/(B(1 - x)))^2)];
gam2[x_] := Exp[B/((1 + (B(1 - x))/(A x))^2)];
PB[x_] := x gam1[x]P1 + (1 - x)gam2[x]P2;
y1[x_] := x gam1[x]P1/PB[x];
plt1 = Plot[Evaluate[PB[x]], {x, 0, 1}, Axes -> False, PlotRange -> All, 
        PlotStyle -> RGBColor[0, 0, 1], Frame -> True, 
        FrameLabel -> {"X,Y", "P"}]];
        
DPPress[P1_, P2_, A_, B_] := 
  Module[{eqn, gam1, gam2, x, sol, PD}, 
    gam1[x_] := Exp[A/((1 + A x/(B(1 - x)))^2)];
gam2[x_] := Exp[B/((1 + (B(1 - x))/(A x))^2)]; 
    eqn[y_] := {x - y PD/(gam1[x]P1) == 0, 
        1 - x - ((1 - y)PD)/(gam2[x]P2) == 0};
 sol[y_] := 
      FindRoot[Evaluate[eqn[y]], {x, .2, .8}, {PD, 50, 70}, 
        MaxIterations -> 100, DampingFactor -> .4];
plt2 = ListPlot[Table[{y, PD} /. sol[y], {y, 0.01, 0.99, .01}], 
        PlotRange -> All, Axes -> False, PlotJoined -> True, 
        PlotStyle -> RGBColor[1, 0, 0], Frame -> True, 
        FrameLabel -> {"X,Y", "P"}]];
        
    parPressure[species_,temp_,paramList_]:=Module[{mydata,parP,Kvalues},mydata=Map[paramList[#]&,species];
		parP=Map[Exp[#[[1]] - #[[2]]/(temp + 273.15 + #[[3]])]&,mydata]];
		
		
actCoefPlot[A_, B_, species1_, species2_] := 
  Module[{gam1, gam2, x1, x2, x,gamMax}, 
    gam1[x1_, x2_] := Exp[A/(1 + A x1/(B x2))^2];
gam2[x1_, x2_] := Exp[B/(1 + B x2/(A x1))^2];
gamMax=gam1[.15, .85]; 
Plot[Evaluate[{gam1[x, 1 - x], gam2[x, 1 - x]}], {x, 0, 1}, 
      PlotStyle -> {RGBColor[0, 0, 1], RGBColor[1, 0, 0]}, 
      FrameLabel -> {"X:" <> ToString[species1], "  \!\(\*
StyleBox[\"γ\",\nFontSize->14]\)"}, Frame -> True, 
      Epilog -> {Text["\!\(\*
StyleBox[\"___\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"_\",\nFontColor->RGBColor[0, 0, 1]]\)" <> ToString[species1], {.4,
               .95 gamMax}, {-1, 0}], Text["\!\(\*
StyleBox[\"___\",\nFontColor->RGBColor[1, 0, 0]]\)\!\(\*
StyleBox[\"_\",\nFontColor->RGBColor[1, 0, 0]]\)" <> ToString[species2], {.4,
               .75 gamMax}, {-1, 0}]}]];

nonIdealSoln.msp

<%Mathlet Get["SpeciesFunc.m"] %>
<html>

	<head>
		<meta name="generator" content="Adobe GoLive 4">
		<title>Non-Ideal Solutions</title>
		<Script Language=JAVASCRIPT>
	
	
	</Script>
	
	</head>

	<body bgcolor="white">
	
			<center><h4>Non-Ideal Solutions<br>
			</h4>
		
				
		<font size=2>Use the form below to select a non-ideal binary mixture for analysis<br>
		 For background information on non-ideal solutions, click, <A href="javascript:sideBar2Window('../../../WRIDevConf/BatchDist.html')">  here<a>
		<p>
		<%Mathlet MSPBlock[{$$n}, mylist=binarySpeciesList[ToString[$$binaryMixture]];]%>
		<p>
		<%Mathlet MSPBlock[{$$n}, binaryParam=BinaryParamList[$$binaryMixture];] %>
		<p>
		<%Mathlet MSPBlock[{$$n}, antoineparam=Map[paramList[#]&,mylist];] %>
			<form onSubmit="return submitData(this)" name="FormName" action="nonIdealSoln" method="post">
		<table align=center>
		<tr>
		<td align=center><font size=2>Temperature (C)</font></td>
		<td><input type=text name=T value="70" size='6'></td>
		
		<td><select name=binaryMixture>
	
		<%Mathlet MSPFunction[{},speciesOption[

		
			Module[ {my1, res},JavaBlock[
			AppendTo[$ExtraClassPath, "C:\myJavaClasses:"];
				my1 = LoadClass["binaryMixture"];
				res=binaryMixture`DBConnect[]]
			] ]]%>
		
		
		</select></td>
		<input type=hidden name=n value="1">
		</tr></tr></table>
		<br>&nbsp</br>
		<table align=center>
		<tr><td><input type=submit name=submit value='Select Binary Mixture'>
		</td>
		</tr>
		</table>
			
	
		</center>
		
		<p>
		<%Mathlet MSPBlock[{$$n, $$T},parP=parPressure[mylist,$$T,paramList];]%>
		
		
		 <p><p>&nbsp</p><p>&nbsp</p>
		 <%Mathlet MSPBlock[{$$n},"<Table align=center border=1 cellspacing=0 cellpadding=5>
		 <tr><th align=center bgcolor=yellow colspan=2>Activity Coefficients and Phase Diagram for "<>ToString[$$binaryMixture]<>" (
		 T="<>ToString[$$T]<>" C)</th></tr>
		 <tr><td>"]%>
		 <%Mathlet MSPBlock[{$$n},MSPShow[actCoefPlot[binaryParam[[1]],binaryParam[[2]],
		 mylist[[1]],mylist[[2]]]]]%>
		 
		 </td><td>
		 <%Mathlet MSPBlock[{$$n},plt1=BPPress[First[parP], Last[parP], binaryParam[[1]],
		 binaryParam[[2]]];plt2=DPPress[First[parP], Last[parP], binaryParam[[1]], 
		 binaryParam[[2]]];MSPShow[Show[plt1,plt2]]]%>
		
		 </td></tr></table>
		
		<center><p>
		<%Mathlet MSPBlock[{$$n},If[ToExpression[binaryParam[[3]]]<ToExpression[$$T]<ToExpression[binaryParam[[4]]],"","<font size=2 color=red>Warning:
		The temperature T="<>ToString[$$T]<>" C selected for the phase diagram calculations<br> lies outside 
		the temperature range ("<>ToString[binaryParam[[3]]]<>"< T <"<>ToString[binaryParam[[4]]]<>") used for the van Laar correlation! </font>"]]%>
		</p></center>
		</body>

</html>

Summary

(i) webMathematica with other server technology (MYSQL, Java Servlets, PHP, etc) has tremendous potential to transform mathematical and computational  explorations in education!
(ii) The design of the user interface remains a key issue, especially if one plans to use webMathematica for interactive learning using a site with multiple outcomes.
(iii) Database connectivity is needed for complex sites. Accessing a JDBC driver via JLink seems to work well.
(iv) One needs a sound knowledge of web page scripting languages to design effective user interfaces.

Acknowledgements

Many thanks to Tom Wickham-Jones, Wolfram Research for expert help during the beta testing program.

Appendices

Isothermal Flash

Introduction

A flash unit is used to separate components based on their relative volatilities. Let us suppose we have a feed stream consisting of N components. If the stream is a liquid phase, one method for partially separating the components is by heating the stream and then expanding the stream adiabatically across a valve to a lower pressure. This results in the creation of a vapor phase, which can then be separated from the residual liquid in a flash drum, taken to be an equilibrium stage. A schematic of the process is shown in Figure 1.

An example of the phase diagram for a binary mixture (ideal) is shown below.

The point (Subscript[P, B])is called the bubble point pressure. This is the pressure at which a given liquid mixture at a given temperature will first form a gas bubble. The point (Subscript[P, D])is called the dew point pressure. This is the pressure at which a  given vapor mixture at a given temperature will first form a liquid drop.

The feed stream to the flash unit is denoted as F[1], the vapor and liquid streams leaving the flash unit are F[2] and F[3]. In a similar manner we denote the temperatures and pressures of the (m^th) stream by T[m] and P[m]. The mole fraction of the (i^th)species in the (m^th) stream is x[i, m]. With this nomenclature we can write down the governing equations for the flash unit. First we have the mole fraction constraints for the individual streams:

			(∑_(i = 1)^N) x[i, 1]=1, (∑_(i = 1)^N) x[i, 2]=1,  (∑_(i = 1)^N) x[i, 3]=1 
		
For each species we can write a material balance over the unit:

			F[1] x[i, 1] = F[2] x[i, 2] + F[3] x[i, 3]   ,      i = 1, 
      2,  …,  N
			
Since the phases are in equilibrium, we have the following thermodynamic relations:

			T[2] = T[3],    P[2] = P[3], 
			
			K[i] = x[i, 2]/x[i, 3],   i = 1, 2, …, N

where K[i] is the K-value for species i. Finally we can write an energy balance over the system. If h[m] is the enthalpy/mole of the (m^th) stream, and Q is the heat added to the feed stream F[1], then

			F[1] h[1] + Q = F[2] h[2] + F[3] h[3]
			
Thus we have 2  N+6 equations. Consider next all the variables defined for the system. They are F[1], F[2], F[3], Q, T[1], T[2], T[3], P[1], P[2], P[3], plus 3  N compositions for a total of 3  N + 10 variables. The number of degrees of freedom for the system are

			ℱ = 3  N + 10 - (2  N + 6) = N + 4

Thus in order to solve the system of equations, we need to specify N + 4 variables. Normally, this is accomplished by specifying N-1 feed compositions (recall we cannot specify N compositions as we have included a mole fraction constraint for the feed stream), plus 5 additional variables. For an isothermal flash calculation we specify F[1], T[1], P[1], T[3], P[3].  For an adiabatic flash we specify F[1], T[1], P[1], Q = 0, P[3]. Clearly other possibilities exist depending on the system specifications.

If we assume the vapor and liquid phases behave ideally, then

				K[i] = (P^sat)[i]/P
				
where (P^sat)[i] is the vapor pressure for species i. We can determine K[i] using the Antoine equation for vapor pressures.

In the isothermal case, we are given T[1], T[2], P[1], P[2], x[i, 1], F[1], and Q = 0.

Batch Distillation

Introduction

Batch distillation with no reflux was analyzed by Lord Rayleigh and is called differential distillation. The key assumption in differential distillation is that the vapor leaving the still is in equilibrium with the liquid  in the still. A schematic of the process is shown below

For a gas/liquid system, the equilibrium relation for species i is  given by

				(Subscript[y, i]) = (Subscript[γ, i]) ((Subscript[x, i])) (((Subscript[P, i]^sat) (T))/(Subscript[P, T])) 
          (Subscript[x, i])	 
				
where (Subscript[P, T ]) is the total pressure, (Subscript[γ, i]) is the activity coefficient, and (Subscript[P, i]^sat)  is the saturation partial pressure. For mixtures with wide boiling points, T is not constant during distillation.

We consider a binary system. If L (t) denotes the moles of liquid in the  batch still at time t, then a species balance for component 1 gives

		(d/d)  t ((Subscript[x, 1]) 
                L) + (Subscript[y, 1]) V = 0

where (Subscript[y, 1])is the mole fraction of species 1 in the gas phase, and V the molar flow rate of vapor leaving the still. Note that the distillate rate  V depends on the rate of heat input to the still. An overall material balance gives

		 d (L/d) t + V = 0
 
 These two equations can be combined to give
 
 		\(\(x\_1\) dL\/d\ t + 
          L d\ x\_1\/d\ t = \(y\_1\) d\ L\/d\ t\)
 
  Regrouping terms gives
  
  		((Subscript[x, 1]) - (Subscript[y, 1]))\(dL\/dt = \(-L\) dx\_1\/dt\)

This is an autonomous equation so we can rewrite the equation in terms of dL/d(Subscript[x, 1]).  The result is 
 
 		d(L/d)(Subscript[x, 1]) = (L/((Subscript[y, 1]) -  (Subscript[x, 1])))
  
  If we impose the process equilibrium equation
  
  		(Subscript[y, 1]) = (Subscript[K, 1]) (Subscript[x, 1])
   
   where for an ideal gas/liquid mixtures we have
   
   		(Subscript[y, 1]) = (((Subscript[P, i]^sat) (T))/(Subscript[P, T])) (Subscript[x, 1])

As the batch distillation proceeds, the temperature of the liquid mixture is at its bubble point, and if the still is operated at constant pressure, then the temperature must vary as the composition in the still changes. This means that (Subscript[K, 1])is not a constant, especially for wide-boiling mixtures.

The saturation pressure is a function of temperature, and is usually correlated with an Antoine equation

		(Subscript[P, 1]^sat) = Exp[(A + (B/(T +  C)))]
  
If we specified the liquid composition and total pressure (Subscript[P, T]), then the bubble point temperature is given by

		(∑_(i = 1)^2) (Subscript[y, i])=(∑_(i = 1)^2) (Subscript[K, i]) (Subscript[x, i])=1

 Thus the equation
 
 		(Subscript[K, 1]) (Subscript[x, 1]) + (Subscript[K, 2]) (Subscript[x, 2]) = 1
  
determines the temperature for a given liquid composition

The mathematical problem then is to solve

		d (L/d) (Subscript[x, 1]) = 
        (L/((Subscript[x, 1]) ( (Subscript[K, 1]) -  1))),   L ((Subscript[x, 10])) = (Subscript[L, 0])
 
where (Subscript[x, 10])is the mole fraction of species 1 at time t = 0. This ODE must be solved subject to the algebraic constraint
 
 		(Subscript[K, 1]) (Subscript[x, 1]) + (Subscript[K, 2]) (Subscript[x, 2]) = 1
  
which determines the bubble temperature. Equations of this type are known as a differential algebraic system of equations (DAE). The approach we will use to solve this system is to convert the algebraic constraint into a differential equation.

We differentiate the algebraic constraint with respect to (Subscript[x, 1]):
 
		(Subscript[x, 1]) d ((Subscript[K, 1])/d)(Subscript[x, 1]) + 
          (Subscript[K, 1]) + (Subscript[x, 2]) d ((Subscript[K, 2])/d)(Subscript[x, 1]) - 
          (Subscript[K, 2]) = 0
 
 Next we use the fact that
  
 		\(d\ K\_i\/dx\_1 = \(d\ 
                K\_i\/dT\) dT\/dx\_1\)
 
 Thus the auxiliary ODE for temperature becomes
 
 	\(d\ T\/dx\_1 = \(K\_2 - \ K\_1\)\/\(\(x\_1\) d\ K\_1\/dT + \ \(x\_2\) d\ K\_2\/dT\)\),  T ((Subscript[x, 10])) = (Subscript[T, 0])
 	
where (Subscript[T, 0]) is the bubble point temperature at the start of the distillation. These equations can be readily solved using Mathematica.

Bubble Point and Dew Point Pressures Calculations

We outline below how one can determine the bubble point and dew point of a binary mixture when we have the equilibrium relation given by Eqn (1) (see Abstract).  We will consider calculations when the temperature is fixed.

If we are given the temperature T and liquid composition (Subscript[x, 1]), then summing the equilibrium relation over the two species gives

(∑_(i = 1)^2) (Subscript[y, i]) (Subscript[P, total])=(∑_(i = 1)^2) (Subscript[γ, i]) (Subscript[x, i]) (Subscript[P, i]^sat)=(Subscript[P, total])

For a given T and (Subscript[x, 1])we can solve the above equation to find (Subscript[P, total]). Once we have found (Subscript[P, total]) we can use the following to find (Subscript[y, 1])

(Subscript[y, 1]) = (((Subscript[γ, 1]) (Subscript[x, 1]) (Subscript[P, 1]^sat))/(Subscript[P, total]))

Here is a sample calculation for ethanol(1)- n-hexane(2) at T= 58°C. We will use the van Laar model for the activity coefficients. The vapor pressures of the pure components at the given temperature are
		(Subscript[P, i]^sat) = 323.5 mmHg,     (Subscript[P, 2]^sat) = 537.1 mmHg 
The van Laar equations for a two component system are given by

(Subscript[γ, 1]) = Exp[(A/(((1 +  ((A (Subscript[x, 1]))/(B (Subscript[x, 2])))))^2))], (Subscript[γ, 2]) = Exp[(B/(((1 +  ((B (Subscript[x, 2]))/(A (Subscript[x, 1])))))^2))]

The van Laar constants for ethanol(1) - n-hexane(2) system are
		A = 2.409,   B = 1.970

Consider next the calculation of the dew point pressure for this system for a given T and (Subscript[y, 1]). At equilibrium the following equations must be satisfied for a given value of (Subscript[y, 1]):

\(x\_1 = \(\(y\_1\) P\_D\)\/\(\(γ\_1\) P\_1\%sat\), \ \ \ x\_2 = \(\((1 - y\_1)\) P\_D\)\/\(\(γ\_2\) P\_2\%sat\), \ \ x\_1 + 
          x\_2 = 1\)

Mathematica Code Bubble Point and Dew Point Pressures Calculations

γ1[x_] := 
      Exp[(2.409/(((1 + ((2.409 x)/(1.970 (1 - x)))))^2))]
γ2[x_] := 
      Exp[(1.970/(((1 + ((1.970 (1 -  x))/(2.409 x))))^2))]
P[1] = 323.5;
P[2] = 537.1;
(Subscript[P, B])[x_] := 
      x γ1[x] P[1] + (1 - x) γ2[x] 
          P[2]
y1[x_] := ((x γ1[x] P[1])/(Subscript[P, B]))[x]

We can use the above definitions to generate a (Subscript[P, total])-x  plot, which is the bubble point pressure.

plt1 = 
        Plot[Evaluate[(Subscript[P, B])[x]], {x, 0, 1}, PlotRange -> {300, 800}, 
          PlotStyle -> RGBColor[0, 0, 1], Frame -> True, 
          FrameLabel -> {"X", "P"}, 
          DisplayFunction -> Identity];

The Mathematica code for dew point calculations is given below

eqn[y_] := {x - ((y (Subscript[P, D]))/(γ1[x] P[1])) == 0, 
        1 - x - (((1 - y) (Subscript[P, D]))/(γ2[x] P[2])) == 0}

sol[y_] := 
        FindRoot[Evaluate[eqn[y]], {x,  .2,  .8}, {(Subscript[P, D]), 600, 500}, 
          MaxIterations -> 100, 
          DampingFactor ->  .4]
plt2=ListPlot[Table[{y, (Subscript[P, D])} /. sol[y], {y, 0.01, 0.99,  .01}],PlotRange -> {300, 800},PlotJoined -> True,PlotStyle -> RGBColor[1, 0, 0],Frame -> True, FrameLabel->{"X,Y","P"},DisplayFunction -> Identity];

Show[plt2, plt1, 
        DisplayFunction -> $DisplayFunction];

Shown below is the P-x-y plot for this system. Note the presence of an azeotrope at x ≈ 0.4