#!/usr/bin/env perl -w
require Tk;
use Tk;
use Tk::Font;
use Tk::Text;
use Tk::ROText;
use English;
use strict;
use warnings;
our %density = (
DI => "1.0",
HF => "1.16",
NH4OH => "0.9",
H202 => "1.11",
HCl => "1.18",
H2SO4 => "1.84",
Citric => "1",
NH4F => "1.01",
TMAH => "1.0",
Nitric => "1.415",
Acetic => "1.05",
Phosphoric => "1.7",
IPA => "0.79"
);
our %concentration =(
DI => "1.0",
HF => "0.49",
NH4OH => "0.29",
H202 => "0.3",
HCl => "0.37",
H2SO4 => ".98",
Citric => "0.5",
NH4F => "0.4",
TMAH => "0.25",
Nitric => "0.7",
Acetic => "0.8",
Phosphoric => "0.85",
IPA => "1.0"
);
my $mw = MainWindow->new;
$mw -> title("BathCalc Selection");
$mw -> geometry("+200+200");
#Setting frames in main window.
my $menuframe = $mw -> Frame(
-relief => "groove",
-borderwidth => 2
)->pack(
-side => "top",
-fill => "x",
);
my $topframe = $mw -> Frame()->pack(
-side => "top",
-fill => "x",
-padx => 10,
-pady => 5
);
my $midframe = $mw -> Frame()->pack(
-side => "top",
-fill => "x",
-padx => 10,
);
my $botframe = $mw -> Frame()->pack(
-side => "top",
-fill => "x",
-padx => 10,
-pady => 5
);
#command to make a file menubutton
my $file_mw = $menuframe -> Menubutton (
-text => "File",
-activeforeground => "grey"
) -> pack (-side => 'left');
$file_mw -> command(
-label => "Exit",
-command => sub{$mw -> destroy}
);
my $help_mw = $menuframe -> Menubutton (
-text => "Help",
-activeforeground => "grey"
) -> pack (-side => 'right');
$help_mw -> command(
-label => "About",
-command => sub{&ABOUT});
#setting up selections as to where to go next
my $rb;
my $r1=$midframe->Radiobutton(
-text=>"Calculate Amount of Material to Pour a Bath",
-value=>"1",
-variable=>\$rb
) -> pack(-side => 'top', -anchor => 'w');
my $r2=$midframe->Radiobutton(
-text=>"Convert Chemical Ratio to Mass Percent",
-value=>"2",
-variable=>\$rb
) -> pack(-side => 'top', -anchor => 'w');
my $r3=$midframe->Radiobutton(
-text=>"Display Assumptions",
-value=>"3",
-variable=>\$rb
) -> pack(-side => 'top', -anchor => 'w');
my $text1 = $topframe->Label (
-text => "Selection:",
-font => '{times new roman} 14'
) -> pack(-side => 'top', -anchor => 'w');
my $actionButton = $botframe -> Button(
-text => "Go",
-command => \&CHOOSE
) -> pack(-side => 'left', -padx => '50', -pady => '20');
my $exitButton = $botframe -> Button(
-text => "Quit",
-command => sub{exit}
) -> pack(-side => 'right', -padx => '50', -pady => '20');
MainLoop ();
sub CHOOSE
{
if ($rb == 1)
{
&MAKE_BATH;
}
elsif ($rb == 2)
{
∶
}
elsif ($rb == 3)
{
&ASSUME;
}
}
######################################################################
+######
######################################################################
+######
# This creates the window for the make bath screen
#
# This subroutine will generate a new window that will require user i
+nput to calculate volumes
# density will be displayed and allow users to change if they need to
+ do so.
# required to pour up a bath of known size and concentration. The de
+fault concentration and
#
#
# MAIN -> MB
######################################################################
+#####
sub MAKE_BATH
{
my $mb = MainWindow -> new;
$mb -> title("Bath Pour Up");
$mb -> geometry("+200+200");
#this frame is going to be the menu bar.
my $frame1 = $mb -> Frame(
-relief => "groove",
-borderwidth => 3
)->pack(
-side => "top",
-fill => "x"
);
my $file_mb = $frame1 -> Menubutton (
-text => "File",
-activeforeground => "grey"
) -> pack (-side => 'left');
$file_mb -> command(
-label => "Exit",
-command => sub{$mb -> destroy});
my $help_mb = $frame1 -> Menubutton (
-text => "Help",
-activeforeground => "grey"
) -> pack (-side => 'right');
$help_mb -> command(
-label => "Help",
-command => sub{&MBHELP}
);
$help_mb -> separator();
$help_mb -> command(
-label => "About",
-command => sub{&ABOUT}
#The next section sets up all of the frames I will need, many, many fr
+ames...
);
my $midhold = $mb -> Frame()->pack(
-side => "top",
-fill => "x",
-padx => 3
);
my $frame2 = $midhold -> Frame()->pack(
-side => "top",
-anchor => "n"
);
my $frame3 = $midhold -> Frame()->pack(
-side => "top",
-anchor => "n"
);
my $calcVolframe = $mb -> Frame(
-borderwidth => 3
)->pack(
-side => "top",
-fill => 'x',
);
my $frame12 = $mb -> Frame( #this is the bottom frame with the st
+atus button in it.
-relief => "raised",
-borderwidth => 3
)->pack(
-side => "bottom",
-fill => 'x',
);
our $totalvolume;
my $voltext = $calcVolframe -> Entry(
-textvariable => \$totalvolume,
-width => 5
) -> pack(
-side => 'right',
-padx => 36);
my $volLbl = $calcVolframe ->Label(
-text => "Bath Volume (L):"
) -> pack(-side=>'right');
#------------------------------------------------------------
#Calculate Button Below
#------------------------------------------------------------
my $calcButton = $calcVolframe -> Button(
-text => "Calculate",
-command => \&VOLCALC
) -> pack(-side => 'left', -padx => '50', -pady => '10');
#------------------------------------------------------------
#Calculate Button Above
#------------------------------------------------------------
our $i = 0;
our(@wtpercent, @wtpercentbox, @concentration, $isSolv, @volume, @
+density, %chemname, @volumebox);
my (@concentrationbox, @densitybox);
#need to make sure that concentration and density are always in th
+e same order.
my $j = 0;
foreach (sort keys(%concentration)){
$concentration[$j] = $concentration{$_};
$density[$j] = $density{$_};
$chemname{$_} = $j;
$wtpercent[$j] = 0;
$j++;
};
my $headingOne = $frame3 ->Label(
-text => "Solvent",
-relief => "raised"
) -> grid (-column=>0, -row => 1);
my $headingTwo = $frame3 ->Label(
-relief => "raised",
-text => "Chemical Name"
) -> grid (-column=>1, -row => 1);
my $headingThree = $frame3 ->Label(
-relief => "raised",
-text => "Density (g/mL)"
) -> grid (-column=>2, -row => 1);
my $headingFour = $frame3 ->Label(
-text => "Concentration (%)",
-relief => "raised"
) -> grid (-column=>3, -row => 1);
my $headingFive = $frame3 ->Label(
-text => "Wt %",
-relief => "raised",
-width => 5
) -> grid (-column=>4, -row => 1);
my $headingSix = $frame3 ->Label(
-text => "Calculated Volume (L)",
-relief => "raised"
) -> grid (-column=>5, -row => 1);
for my $x (sort keys %density) {
my $row = $i+2;
$frame3->Radiobutton(
-value=>$i,
-variable => \$isSolv,
-command=>[\&colorme, $i])->grid(-row=>$row,-column=>0);
$frame3->Label(-text=>$x)->grid(-row=>$row,-column=>1);
$densitybox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -te
+xtvariable => \$density[$i])->grid(-row=>$row,-column=>2);
$concentrationbox[$i] = $frame3->Entry(-bg=>'grey', -width =>
+5, -textvariable => \$concentration[$i])->grid(-row=>$row,-column=>3)
+;
$wtpercentbox[$i] = $frame3->Entry(-bg=>'white', -width => 5,
+-textvariable => \$wtpercent[$i])->grid(-row=>$row,-column=>4);
$volumebox[$i] = $frame3->Entry(-bg=>'grey', -width => 7, -tex
+tvariable => \$volume[$i])->grid(-row=>$row,-column=>5);
$i++;
}
our $statustext = "Please enter desired weight percent and sol
+vent.";
my $statuslabel = $frame12 -> Label(
-text => "Status: "
) -> pack(-side => "left");
my $status =$frame12 -> Entry(
-textvariable => \$statustext,
-foreground => 'red',
-width => 60
) -> pack(-side => "left");
}
######################################################################
+######
######################################################################
+######
# This creates the window for the ratio screen
#
# MAIN -> RATIO
######################################################################
+#####
sub RATIO
{
my $rt = MainWindow -> new;
$rt -> title("Ratio to Weight Percent");
$rt -> geometry("+200+200");
#this frame is going to be the menu bar.
my $frame1 = $rt -> Frame(
-relief => "groove",
-borderwidth => 3
)->pack(
-side => "top",
-fill => "x"
);
my $file_rt = $frame1 -> Menubutton (
-text => "File",
-activeforeground => "grey"
) -> pack (-side => 'left');
$file_rt -> command(
-label => "Exit",
-command => sub{$rt -> destroy});
my $help_rt = $frame1 -> Menubutton (
-text => "Help",
-activeforeground => "grey"
) -> pack (-side => 'right');
$help_rt -> command(
-label => "Help",
-command => sub{&RTHELP}
);
$help_rt -> separator();
$help_rt -> command(
-label => "About",
-command => sub{&ABOUT}
);
#The next section sets up all of the frames I will need, many, many fr
+ames...
my $midhold = $rt -> Frame()->pack(
-side => "top",
-fill => "x",
-padx => 3
);
my $frame2 = $midhold -> Frame()->pack(
-side => "top",
-anchor => "n"
);
our $rtframe3 = $midhold -> Frame()->pack(
-side => "top",
-anchor => "n"
);
our $calcVolframe = $rt -> Frame(
-borderwidth => 3
)->pack(
-side => "top",
-fill => 'x',
);
my $frame12 = $rt -> Frame( #this is the bottom frame with the st
+atus button in it.
-relief => "raised",
-borderwidth => 3
)->pack(
-side => "bottom",
-fill => 'x',
);
our $VolButton = $calcVolframe -> Button(
-text => "Bath Volume >>",
-command => \&RATIOSUP
) -> pack(-side => 'right', -padx => '5', -pady => '5');
our $mOrv;
my $mOrvbutton = $calcVolframe -> Radiobutton(
-variable => \$mOrv,
-value => "M",
-width => 5
) -> pack(
-side => 'right');
my $massText = $calcVolframe -> Label(
-text => "Mass Ratio ",
-padx => 2) -> pack(-side => "right");
my $mOrvbutton2 = $calcVolframe -> Radiobutton(
-variable => \$mOrv,
-value => "V",
-width => 5
) -> pack(
-side => 'right');
my $volLbl = $calcVolframe ->Label(
-text => "Volume Ratio:"
) -> pack(-side=>'right');
#------------------------------------------------------------
#Calculate Button Below
#------------------------------------------------------------
my $calcButton = $calcVolframe -> Button(
-text => "Calculate",
-command => \&RATIOCALC
) -> pack(-side => 'left', -padx => '50', -pady => '10');
#------------------------------------------------------------
#Calculate Button Above
#------------------------------------------------------------
our(@ratio, @ratiobox, @concentration, @wtPercent, @density, %chem
+name, @wtpercentbox, @ratioVolbox, @ratioVol);
my (@concentrationbox, @densitybox);
#need to make sure that concentration and density are always in th
+e same order.
my $j = 0;
foreach (sort keys(%concentration)){
$concentration[$j] = $concentration{$_};
$density[$j] = $density{$_};
$chemname{$_} = $j;
$ratio[$j] = 0;
$wtPercent[$j] = 0;
$j++;
};
my $headingTwo = $rtframe3 ->Label(
-relief => "raised",
-text => "Chemical Name"
) -> grid (-column=>1, -row => 1, -padx => 3, -pady =>2);
my $headingThree = $rtframe3 ->Label(
-relief => "raised",
-text => "Density (g/mL)"
) -> grid (-column=>2, -row => 1, -padx => 3, -pady =>2);
my $headingFour = $rtframe3 ->Label(
-text => "Concentration",
-relief => "raised"
) -> grid (-column=>3, -row => 1, -padx => 3, -pady =>2);
+
my $headingFive = $rtframe3 ->Label(
-text => "Ratio",
-relief => "raised",
-width => 5
) -> grid (-column=>4, -row => 1, -padx => 3, -pady =>2);
my $headingSix = $rtframe3 ->Label(
-text => "Calculated Wt Percent",
-relief => "raised"
) -> grid (-column=>5, -row => 1, -padx => 3, -pady =>2);
my $i = 0;
for my $chems (sort keys %density) {
my $row = $i+2;
$rtframe3->Label(-text=>$chems)->grid(-row=>$row,-column=>1);
$densitybox[$i] = $rtframe3->Entry(-bg=>'grey', -width => 5, -
+textvariable => \$density[$i], -justify => "center")->grid(-row=>$row
+,-column=>2);
$concentrationbox[$i] = $rtframe3->Entry(-bg=>'grey', -width =
+> 5, -textvariable => \$concentration[$i], -justify => "center")->gri
+d(-row=>$row,-column=>3);
$ratiobox[$i] = $rtframe3->Entry(-bg=>'white', -width => 5, -t
+extvariable => \$ratio[$i], -justify => "center")->grid(-row=>$row,-c
+olumn=>4);
$wtpercentbox[$i] = $rtframe3->Entry(-bg=>'grey', -textvariabl
+e => \$wtPercent[$i], -width => 5, -justify => "center")->grid(-row=
+>$row,-column=>5);
$i++;
}
our $statustext = "Please enter desired ratio and whether wt o
+r vol percent.";
my $statuslabel = $frame12 -> Label(
-text => "Status: "
) -> pack(-side => "left");
my $status =$frame12 -> Entry(
-textvariable => \$statustext,
-foreground => 'red',
-width => 60
) -> pack(-side => "left");
}
######################################################################
+######
######################################################################
+######
# This sub is responsible for calculating the wt percents of the che
+micals
# supplied in the ratio screen
# MAIN -> MB -> VOLCALC
######################################################################
+#####
sub VOLCALC
{
our(@wtpercent, @wtpercentbox, @concentration, @volume, @density,
+%chemname, @volumebox, $isSolv, $statustext, $totalvolume);
my @densityfraction;
if (defined($totalvolume)){
if (defined($isSolv)){
my @chemname = (sort keys(our %density));
my $solventname = $chemname[$isSolv];
$statustext = "Calculating";
my @concRatio;
$wtpercent[$isSolv] = 0;
for (my $i=0; $i <= $#chemname; $i++){
$concRatio[$i] = (.01 * $wtpercent[$i]) / $concentrati
+on[$i];
$densityfraction[$i] = $concRatio[$i] * $density[$i];
}
my $percentsolvent = 1 - sum(@concRatio);
my $densityfractionsolvent = $percentsolvent * $density[$i
+sSolv];
$densityfraction[$isSolv] = $densityfractionsolvent;
my $estdensity = sum(@densityfraction);
my $totalmass = $totalvolume * $estdensity;
my @componentmass = map{$_ * $totalmass}@concRatio;
my $i;
for ($i=0; $i <= $#componentmass; $i++){
$volume[$i] = $componentmass[$i] / $density[$i];
}
my $volumewithoutsolvent = sum(@volume);
$volume[$isSolv] = $totalvolume - $volumewithoutsolvent;
$statustext = ("Calculation Complete");
my $l = 0;
foreach (@volume){
$volume[$l] = sprintf("%.3f", $volume[$l]);
$l++;
};
foreach (@volume){
if ($_ < 0){
$statustext = "You screwed up somewhere!"
}
}
}
else
{
$statustext = "You need to select a solvent"
}
}
else
{
$statustext = "You need to provide a bath volume";
}
};
######################################################################
+######
######################################################################
+######
# This sub is responsible for calculating the wt percents of the che
+micals
# supplied in the ratio screen
# MAIN -> RT -> RATIOCALC
######################################################################
+#####
sub RATIOCALC
{
our ($mOrv, @ratio, @density, @concentration, %chemname, @wtPercen
+t, $statustext, @wtpercentbox);
our (@volratio, $totalVol, @ratioVol);
my (@wtPureAmt, @residualDI);
if (defined($mOrv)){
$statustext = "Calculating...";
if ($mOrv eq "V"){
for (my $i = 0; $i <= $#ratio; $i++){
$ratio[$i] = $ratio[$i] * $density[$i];
$mOrv = "M";
};
};
for (my $j = 0; $j <= $#ratio; $j++){
$wtPureAmt[$j] = $ratio[$j] * $concentration[$j];
};
for (my $k = 0; $k <= $#ratio; $k++){
$residualDI[$k] = $ratio[$k] * (1 - $concentration[$k]);
};
my $totalmass = sum(@ratio);
my $diIndex = $chemname{'DI'};
if ($totalmass != 0){@wtPercent = map{$_ / $totalmass}@wtPureA
+mt}else{$statustext = "You need to give me numbers!"};
if ($wtPureAmt[$diIndex] == 0)
{
$wtPercent[$diIndex] = sum(@residualDI) / $totalmass;
}
else
{
$wtPercent[$diIndex] = (sum(@residualDI) + $wtPureAmt[$diI
+ndex]) / $totalmass;
}
$statustext = "Calculation Complete";
}else{
$statustext = "You need to select weight or volume ratio!"
};
my $l = 0;
foreach (@wtPercent){
$wtPercent[$l] = sprintf("%.3f", $wtPercent[$l]);
$wtPercent[$l] = $wtPercent[$l] * 100;
$wtpercentbox[$l] -> configure( -textvariable => \$wtPercent[$
+l]);
$l++;
};
if ($totalVol != 0){
if (our $volEntryOpen == 1){
if ($mOrv eq "M"){
for (my $i = 0; $i <= $#ratio; $i++){
$volratio[$i] = $ratio[$i] / $density[$i];
};
};
my $j;
for ($j=0; $j <= $#volratio; $j++){
$ratioVol[$j] = $totalVol * ($volratio[$j] / sum(@volr
+atio));
$ratioVol[$j] = sprintf("%.3f", $ratioVol[$j]);
};
}
}
else
{
$statustext = "You need to provide a total volume in liters."
};
}
######################################################################
+######
######################################################################
+######
# this subroutine sums the numbers passed to it. Returns a single v
+alue.
#
#
######################################################################
+#####
sub sum
{
my $sum = 0;
foreach my $line (@_)
{
$sum += $line;
}
return $sum;
}
######################################################################
+######
######################################################################
+######
# This subroutine disables and colors the wtpercentbox of the selecte
+d
# solvent in the Make Bath calculation window
# MAIN -> MB -> COLORME
######################################################################
+#####
sub colorme {
our @wtpercentbox;
my $i = shift;
map{$_->configure(-bg=>'white')}@wtpercentbox;
$wtpercentbox[$i]->configure(-bg=>'black');
map{$_->configure(-state=>'normal')}@wtpercentbox;
$wtpercentbox[$i]->configure(-state => 'disabled');
}
######################################################################
+######
######################################################################
+######
# This window is created when the Bath Volume button is pushed in the
+
# ratio window calculation screen. It will provide the volumes of ch
+emical
# to add to create a bath of known volume
# RT -> RATIO -> RATIOSUP
######################################################################
+#####
sub RATIOSUP
{
our (@ratio, $rtframe3, @ratioVol, @ratioVolbox, $VolButton, $calc
+Volframe, $totalVol, $statustext, $mOrv, @density);
my ($row, @volratio);
my $headingSeven = $rtframe3 ->Label(
-text => "Pour Up Volume (L)",
-relief => "raised"
) -> grid (-column=>6, -row => 1, -padx => 3, -pady =>2);
$VolButton -> packForget;
$statustext = "You need to provide a total volume";
my $i = 0;
foreach my $line (@ratio) {
$row = $i+2;
$ratioVolbox[$i] = $rtframe3->Entry(-bg=>'grey', -width =>
+ 7, -textvariable => \$ratioVol[$i], -justify => 'center')->grid(-row
+=>$row,-column=>6);
$i++;
}
my $newrow = $row +1;
our $totvolbox = $rtframe3 -> Entry(-bg => 'white', -width => 7, -
+textvariable => \$totalVol, -justify => 'center') -> grid (-row=>$new
+row, -column => 6, -pady => 3);
my $totvolLab = $rtframe3 -> Label(-text => "Total Volume (L)") ->
+ grid (-row=>$newrow, -column => 5, -pady => 3);
our $volEntryOpen = 1;
}
######################################################################
+######
######################################################################
+######
# This window is the about box for all windows
#
# MAIN -> ABOUT
######################################################################
+#####
sub ABOUT #The about box in the help menu!
{
my $aboutwin = MainWindow -> new;
$aboutwin -> title("About");
$aboutwin -> geometry("+210+210");
my $aboutleftframe = $aboutwin -> Frame() -> pack(-side => "left")
+;
my $aboutrightframe = $aboutwin -> Frame() -> pack(-side => "left"
+);
my $exitButton = $aboutrightframe -> Button(
-text => "Close",
-command => sub{destroy $aboutwin}
) -> pack(-side => 'right', -padx => '10', -pady => '10');
my $words = qq(
BathCalc ver.2.0
Written by David Daycock.
August 2004
Send bugs to:
david\@netboise.com);
my $aboutText = $aboutleftframe->Scrolled('ROText',
-height => '10',
-width => '20',
-wrap => "word",
-scrollbars => 'osoe',
);
$aboutText -> insert('end', $words);
$aboutText -> pack(-side => "left", -padx => '10', -pady => '10');
}
######################################################################
+######
######################################################################
+######
# This is the HELP MENU in the RATIO CALC window
######################################################################
+#####
sub RTHELP
{
my $rthelpwin = MainWindow -> new;
$rthelpwin -> title("Help");
$rthelpwin -> geometry("+210+210");
my $rthelpleftframe = $rthelpwin -> Frame() -> pack(-side => "left
+");
my $rthelprightframe = $rthelpwin -> Frame() -> pack(-side => "lef
+t");
my $words = qq(
This utility will help you calculate mass percentages and volumes to p
+our up baths.
The concentration and the densities have been provided based on standa
+rd concentrated chemicals. These values are able to be modified by t
+he user. Concentrations are provided in weight fraction, and density
+ in grams per mL.
When you click the "Make Bath" button, you will be prompted to enter a
+ total bath volume in liters.
);
my $rthelpText = $rthelpleftframe->Scrolled('ROText',
-height => '25',
-width => '100',
-wrap => "word",
-scrollbars => 'osoe',
);
$rthelpText -> insert('end', $words);
$rthelpText -> pack(-side => "left", -padx => '10', -pady => '10');
}
######################################################################
+######
######################################################################
+######
# This is the HELP MENU in the MAKE BATH CALC window
######################################################################
+#####
sub MBHELP
{
my $mbhelpwin = MainWindow -> new;
$mbhelpwin -> title("Help");
$mbhelpwin -> geometry("+210+210");
my $mbhelpframe = $mbhelpwin -> Frame() -> pack(-side => "left");
my $words = qq(
This utility will calculate pour up volumes if you have desired final
+wt percent goal.
The wt percent column should be entered as mass fraction * 100. (0.02
+ mass fraction of component A = 2 (wt %));
You will need to provide a total bath volume, then select the solvent.
+ For instance, if I want to pour up 12L of 2% TMAH in DI, you would
+first type in 12 in the Bath Volume box, then click the DI radio butt
+on, then type "2" in wt % box in the TMAH row.
Results are supplied in Liters rounded to the nearest mL.
);
my $mbhelpText = $mbhelpframe->Scrolled('ROText',
-height => '25',
-width => '100',
-wrap => "word",
-scrollbars => 'osoe',
);
$mbhelpText -> insert('end', $words);
$mbhelpText -> pack(-side => "left", -padx => '10', -pady => '10');
}
######################################################################
+######
######################################################################
+######
# This is the Assumptions window from the top main window
######################################################################
+#####
sub ASSUME
{
my $assumewin = MainWindow -> new;
$assumewin -> title("Assumptions");
$assumewin -> geometry("+210+210");
my $assumeframe = $assumewin -> Frame() -> pack(-side => "left");
my $words = qq(
The only assumption you can not modify is this: When calculating bath
+ pour up based on desired weight pecent, the denisty of the total sol
+ution is assumed to be the mass percent weighted averages of the comp
+onents' density.
);
my $assumeText = $assumeframe->Scrolled('ROText',
-height => '25',
-width => '50',
-wrap => "word",
-scrollbars => 'osoe',
);
$assumeText -> insert('end', $words);
$assumeText -> pack(-side => "left", -padx => '10', -pady => '10');
}
|